/*
 * File is generated by scripts/block-coroutine-wrapper.py
 *
 * Copyright (c) 2020 Virtuozzo International GmbH.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "qemu/osdep.h"
#include "block/coroutines.h"
#include "block/block-gen.h"
#include "block/block_int.h"
#include "block/dirty-bitmap.h"



/*
 * Wrappers for bdrv_co_pwrite_zeroes
 */

typedef struct BdrvPwriteZeroes {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    int64_t bytes;
    BdrvRequestFlags flags;
} BdrvPwriteZeroes;

static void coroutine_fn bdrv_co_pwrite_zeroes_entry(void *opaque)
{
    BdrvPwriteZeroes *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_pwrite_zeroes(s->child, s->offset, s->bytes, s->flags);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_pwrite_zeroes(child, offset, bytes, flags);
    } else {
        BdrvPwriteZeroes s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .bytes = bytes,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_pwrite_zeroes_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_pread
 */

typedef struct BdrvPread {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    int64_t bytes;
    void *buf;
    BdrvRequestFlags flags;
} BdrvPread;

static void coroutine_fn bdrv_co_pread_entry(void *opaque)
{
    BdrvPread *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_pread(s->child, s->offset, s->bytes, s->buf, s->flags);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_pread(BdrvChild *child, int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_pread(child, offset, bytes, buf, flags);
    } else {
        BdrvPread s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_pread_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_pwrite
 */

typedef struct BdrvPwrite {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    int64_t bytes;
    const void *buf;
    BdrvRequestFlags flags;
} BdrvPwrite;

static void coroutine_fn bdrv_co_pwrite_entry(void *opaque)
{
    BdrvPwrite *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_pwrite(s->child, s->offset, s->bytes, s->buf, s->flags);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_pwrite(BdrvChild *child, int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_pwrite(child, offset, bytes, buf, flags);
    } else {
        BdrvPwrite s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_pwrite_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_pwrite_sync
 */

typedef struct BdrvPwriteSync {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    int64_t bytes;
    const void *buf;
    BdrvRequestFlags flags;
} BdrvPwriteSync;

static void coroutine_fn bdrv_co_pwrite_sync_entry(void *opaque)
{
    BdrvPwriteSync *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_pwrite_sync(s->child, s->offset, s->bytes, s->buf, s->flags);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_pwrite_sync(child, offset, bytes, buf, flags);
    } else {
        BdrvPwriteSync s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_pwrite_sync_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_getlength
 */

typedef struct BdrvGetlength {
    BdrvPollCo poll_state;
    int64_t ret;
    BlockDriverState *bs;
} BdrvGetlength;

static void coroutine_fn bdrv_co_getlength_entry(void *opaque)
{
    BdrvGetlength *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_getlength(s->bs);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int64_t bdrv_getlength(BlockDriverState *bs)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_getlength(bs);
    } else {
        BdrvGetlength s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_getlength_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_get_allocated_file_size
 */

typedef struct BdrvGetAllocatedFileSize {
    BdrvPollCo poll_state;
    int64_t ret;
    BlockDriverState *bs;
} BdrvGetAllocatedFileSize;

static void coroutine_fn bdrv_co_get_allocated_file_size_entry(void *opaque)
{
    BdrvGetAllocatedFileSize *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_get_allocated_file_size(s->bs);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
{
    BdrvGetAllocatedFileSize s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .bs = bs,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_get_allocated_file_size_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}


/*
 * Wrappers for bdrv_co_block_status
 */

typedef struct BdrvBlockStatus {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
    int64_t *map;
    BlockDriverState **file;
} BdrvBlockStatus;

static void coroutine_fn bdrv_co_block_status_entry(void *opaque)
{
    BdrvBlockStatus *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_block_status(s->bs, s->offset, s->bytes, s->pnum, s->map, s->file);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_block_status(bs, offset, bytes, pnum, map, file);
    } else {
        BdrvBlockStatus s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .offset = offset,
            .bytes = bytes,
            .pnum = pnum,
            .map = map,
            .file = file,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_block_status_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_block_status_above
 */

typedef struct BdrvBlockStatusAbove {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    BlockDriverState *base;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
    int64_t *map;
    BlockDriverState **file;
} BdrvBlockStatusAbove;

static void coroutine_fn bdrv_co_block_status_above_entry(void *opaque)
{
    BdrvBlockStatusAbove *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_block_status_above(s->bs, s->base, s->offset, s->bytes, s->pnum, s->map, s->file);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_block_status_above(bs, base, offset, bytes, pnum, map, file);
    } else {
        BdrvBlockStatusAbove s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .base = base,
            .offset = offset,
            .bytes = bytes,
            .pnum = pnum,
            .map = map,
            .file = file,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_block_status_above_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_is_allocated
 */

typedef struct BdrvIsAllocated {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
} BdrvIsAllocated;

static void coroutine_fn bdrv_co_is_allocated_entry(void *opaque)
{
    BdrvIsAllocated *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_is_allocated(s->bs, s->offset, s->bytes, s->pnum);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_is_allocated(bs, offset, bytes, pnum);
    } else {
        BdrvIsAllocated s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .offset = offset,
            .bytes = bytes,
            .pnum = pnum,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_is_allocated_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_is_allocated_above
 */

typedef struct BdrvIsAllocatedAbove {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    BlockDriverState *base;
    bool include_base;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
} BdrvIsAllocatedAbove;

static void coroutine_fn bdrv_co_is_allocated_above_entry(void *opaque)
{
    BdrvIsAllocatedAbove *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_is_allocated_above(s->bs, s->base, s->include_base, s->offset, s->bytes, s->pnum);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, int64_t offset, int64_t bytes, int64_t *pnum)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_is_allocated_above(bs, base, include_base, offset, bytes, pnum);
    } else {
        BdrvIsAllocatedAbove s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .base = base,
            .include_base = include_base,
            .offset = offset,
            .bytes = bytes,
            .pnum = pnum,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_is_allocated_above_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_is_inserted
 */

typedef struct BdrvIsInserted {
    BdrvPollCo poll_state;
    bool ret;
    BlockDriverState *bs;
} BdrvIsInserted;

static void coroutine_fn bdrv_co_is_inserted_entry(void *opaque)
{
    BdrvIsInserted *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_is_inserted(s->bs);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

bool bdrv_is_inserted(BlockDriverState *bs)
{
    BdrvIsInserted s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .bs = bs,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_is_inserted_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}


/*
 * Wrappers for bdrv_co_get_info
 */

typedef struct BdrvGetInfo {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    BlockDriverInfo *bdi;
} BdrvGetInfo;

static void coroutine_fn bdrv_co_get_info_entry(void *opaque)
{
    BdrvGetInfo *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_get_info(s->bs, s->bdi);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_get_info(bs, bdi);
    } else {
        BdrvGetInfo s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .bdi = bdi,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_get_info_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_change_backing_file
 */

typedef struct BdrvChangeBackingFile {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    const char *backing_file;
    const char *backing_fmt;
    bool warn;
} BdrvChangeBackingFile;

static void coroutine_fn bdrv_co_change_backing_file_entry(void *opaque)
{
    BdrvChangeBackingFile *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_change_backing_file(s->bs, s->backing_file, s->backing_fmt, s->warn);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_fmt, bool warn)
{
    BdrvChangeBackingFile s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .bs = bs,
        .backing_file = backing_file,
        .backing_fmt = backing_fmt,
        .warn = warn,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_change_backing_file_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}


/*
 * Wrappers for bdrv_co_debug_event
 */

typedef struct BdrvDebugEvent {
    BdrvPollCo poll_state;
    
    BlockDriverState *bs;
    BlkdebugEvent event;
} BdrvDebugEvent;

static void coroutine_fn bdrv_co_debug_event_entry(void *opaque)
{
    BdrvDebugEvent *s = opaque;

    bdrv_graph_co_rdlock();
    bdrv_co_debug_event(s->bs, s->event);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        bdrv_co_debug_event(bs, event);
    } else {
        BdrvDebugEvent s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .event = event,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_debug_event_entry, &s);

        bdrv_poll_co(&s.poll_state);
        
    }
}


/*
 * Wrappers for bdrv_co_can_store_new_dirty_bitmap
 */

typedef struct BdrvCanStoreNewDirtyBitmap {
    BdrvPollCo poll_state;
    bool ret;
    BlockDriverState *bs;
    const char *name;
    uint32_t granularity;
    Error **errp;
} BdrvCanStoreNewDirtyBitmap;

static void coroutine_fn bdrv_co_can_store_new_dirty_bitmap_entry(void *opaque)
{
    BdrvCanStoreNewDirtyBitmap *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_can_store_new_dirty_bitmap(s->bs, s->name, s->granularity, s->errp);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, uint32_t granularity, Error **errp)
{
    BdrvCanStoreNewDirtyBitmap s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .bs = bs,
        .name = name,
        .granularity = granularity,
        .errp = errp,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_can_store_new_dirty_bitmap_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}


/*
 * Wrappers for bdrv_co_truncate
 */

typedef struct BdrvTruncate {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    bool exact;
    PreallocMode prealloc;
    BdrvRequestFlags flags;
    Error **errp;
} BdrvTruncate;

static void coroutine_fn bdrv_co_truncate_entry(void *opaque)
{
    BdrvTruncate *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_truncate(s->child, s->offset, s->exact, s->prealloc, s->flags, s->errp);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_truncate(child, offset, exact, prealloc, flags, errp);
    } else {
        BdrvTruncate s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .exact = exact,
            .prealloc = prealloc,
            .flags = flags,
            .errp = errp,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_truncate_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_check
 */

typedef struct BdrvCheck {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    BdrvCheckResult *res;
    BdrvCheckMode fix;
} BdrvCheck;

static void coroutine_fn bdrv_co_check_entry(void *opaque)
{
    BdrvCheck *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_check(s->bs, s->res, s->fix);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_check(bs, res, fix);
    } else {
        BdrvCheck s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .res = res,
            .fix = fix,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_check_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_invalidate_cache
 */

typedef struct BdrvInvalidateCache {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    Error **errp;
} BdrvInvalidateCache;

static void coroutine_fn bdrv_co_invalidate_cache_entry(void *opaque)
{
    BdrvInvalidateCache *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_invalidate_cache(s->bs, s->errp);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_invalidate_cache(bs, errp);
    } else {
        BdrvInvalidateCache s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .errp = errp,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_invalidate_cache_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_flush
 */

typedef struct BdrvFlush {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
} BdrvFlush;

static void coroutine_fn bdrv_co_flush_entry(void *opaque)
{
    BdrvFlush *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_flush(s->bs);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_flush(BlockDriverState *bs)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_flush(bs);
    } else {
        BdrvFlush s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_flush_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_pdiscard
 */

typedef struct BdrvPdiscard {
    BdrvPollCo poll_state;
    int ret;
    BdrvChild *child;
    int64_t offset;
    int64_t bytes;
} BdrvPdiscard;

static void coroutine_fn bdrv_co_pdiscard_entry(void *opaque)
{
    BdrvPdiscard *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_pdiscard(s->child, s->offset, s->bytes);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_pdiscard(child, offset, bytes);
    } else {
        BdrvPdiscard s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .child = child,
            .offset = offset,
            .bytes = bytes,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_pdiscard_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_readv_vmstate
 */

typedef struct BdrvReadvVmstate {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    QEMUIOVector *qiov;
    int64_t pos;
} BdrvReadvVmstate;

static void coroutine_fn bdrv_co_readv_vmstate_entry(void *opaque)
{
    BdrvReadvVmstate *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_readv_vmstate(s->bs, s->qiov, s->pos);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_readv_vmstate(bs, qiov, pos);
    } else {
        BdrvReadvVmstate s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .qiov = qiov,
            .pos = pos,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_readv_vmstate_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for bdrv_co_writev_vmstate
 */

typedef struct BdrvWritevVmstate {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    QEMUIOVector *qiov;
    int64_t pos;
} BdrvWritevVmstate;

static void coroutine_fn bdrv_co_writev_vmstate_entry(void *opaque)
{
    BdrvWritevVmstate *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_writev_vmstate(s->bs, s->qiov, s->pos);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_writev_vmstate(bs, qiov, pos);
    } else {
        BdrvWritevVmstate s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .qiov = qiov,
            .pos = pos,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_writev_vmstate_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}



/*
 * Wrappers for bdrv_co_remove_persistent_dirty_bitmap
 */

typedef struct BdrvRemovePersistentDirtyBitmap {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    const char *name;
    Error **errp;
} BdrvRemovePersistentDirtyBitmap;

static void coroutine_fn bdrv_co_remove_persistent_dirty_bitmap_entry(void *opaque)
{
    BdrvRemovePersistentDirtyBitmap *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_remove_persistent_dirty_bitmap(s->bs, s->name, s->errp);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp)
{
    BdrvRemovePersistentDirtyBitmap s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .bs = bs,
        .name = name,
        .errp = errp,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_remove_persistent_dirty_bitmap_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}



/*
 * Wrappers for bdrv_co_refresh_total_sectors
 */

typedef struct BdrvRefreshTotalSectors {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    int64_t hint;
} BdrvRefreshTotalSectors;

static void coroutine_fn bdrv_co_refresh_total_sectors_entry(void *opaque)
{
    BdrvRefreshTotalSectors *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_refresh_total_sectors(s->bs, s->hint);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_refresh_total_sectors(bs, hint);
    } else {
        BdrvRefreshTotalSectors s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .hint = hint,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_refresh_total_sectors_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}



/*
 * Wrappers for bdrv_co_create
 */

typedef struct BdrvCreate {
    BdrvPollCo poll_state;
    int ret;
    BlockDriver *drv;
    const char *filename;
    QemuOpts *opts;
    Error **errp;
} BdrvCreate;

static void coroutine_fn bdrv_co_create_entry(void *opaque)
{
    BdrvCreate *s = opaque;


    s->ret = bdrv_co_create(s->drv, s->filename, s->opts, s->errp);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_create(BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp)
{
    BdrvCreate s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .drv = drv,
        .filename = filename,
        .opts = opts,
        .errp = errp,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(bdrv_co_create_entry, &s);

    bdrv_poll_co(&s.poll_state);
    return s.ret;
}


/*
 * Wrappers for bdrv_open_child
 */

typedef struct BdrvCoOpenChild {
    Coroutine *co;
    BdrvChild * ret;
    const char *filename;
    QDict *options;
    const char *bdref_key;
    BlockDriverState *parent;
    const BdrvChildClass *child_class;
    BdrvChildRole child_role;
    bool allow_none;
    Error **errp;
} BdrvCoOpenChild;

static void bdrv_open_child_bh(void *opaque)
{
    BdrvCoOpenChild *s = opaque;


    s->ret = bdrv_open_child(s->filename, s->options, s->bdref_key, s->parent, s->child_class, s->child_role, s->allow_none, s->errp);


    aio_co_wake(s->co);
}

BdrvChild * coroutine_fn bdrv_co_open_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, const BdrvChildClass *child_class, BdrvChildRole child_role, bool allow_none, Error **errp)
{
    BdrvCoOpenChild s = {
        .co = qemu_coroutine_self(),
        .filename = filename,
        .options = options,
        .bdref_key = bdref_key,
        .parent = parent,
        .child_class = child_class,
        .child_role = child_role,
        .allow_none = allow_none,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_open_child_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for bdrv_open_blockdev_ref
 */

typedef struct BdrvCoOpenBlockdevRef {
    Coroutine *co;
    BlockDriverState * ret;
    BlockdevRef *ref;
    Error **errp;
} BdrvCoOpenBlockdevRef;

static void bdrv_open_blockdev_ref_bh(void *opaque)
{
    BdrvCoOpenBlockdevRef *s = opaque;


    s->ret = bdrv_open_blockdev_ref(s->ref, s->errp);


    aio_co_wake(s->co);
}

BlockDriverState * coroutine_fn bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp)
{
    BdrvCoOpenBlockdevRef s = {
        .co = qemu_coroutine_self(),
        .ref = ref,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_open_blockdev_ref_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for bdrv_open
 */

typedef struct BdrvCoOpen {
    Coroutine *co;
    BlockDriverState * ret;
    const char *filename;
    const char *reference;
    QDict *options;
    int flags;
    Error **errp;
} BdrvCoOpen;

static void bdrv_open_bh(void *opaque)
{
    BdrvCoOpen *s = opaque;


    s->ret = bdrv_open(s->filename, s->reference, s->options, s->flags, s->errp);


    aio_co_wake(s->co);
}

BlockDriverState * coroutine_fn bdrv_co_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp)
{
    BdrvCoOpen s = {
        .co = qemu_coroutine_self(),
        .filename = filename,
        .reference = reference,
        .options = options,
        .flags = flags,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_open_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for bdrv_activate
 */

typedef struct BdrvCoActivate {
    Coroutine *co;
    int ret;
    BlockDriverState *bs;
    Error **errp;
} BdrvCoActivate;

static void bdrv_activate_bh(void *opaque)
{
    BdrvCoActivate *s = opaque;

    bdrv_graph_rdlock_main_loop();
    s->ret = bdrv_activate(s->bs, s->errp);
    bdrv_graph_rdunlock_main_loop();

    aio_co_wake(s->co);
}

int coroutine_fn bdrv_co_activate(BlockDriverState *bs, Error **errp)
{
    BdrvCoActivate s = {
        .co = qemu_coroutine_self(),
        .bs = bs,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_activate_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for bdrv_unref
 */

typedef struct BdrvCoUnref {
    Coroutine *co;
    
    BlockDriverState *bs;
} BdrvCoUnref;

static void bdrv_unref_bh(void *opaque)
{
    BdrvCoUnref *s = opaque;


    bdrv_unref(s->bs);


    aio_co_wake(s->co);
}

void coroutine_fn bdrv_co_unref(BlockDriverState *bs)
{
    BdrvCoUnref s = {
        .co = qemu_coroutine_self(),
        .bs = bs,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_unref_bh, &s);
    qemu_coroutine_yield();

    
}


/*
 * Wrappers for bdrv_unref_child
 */

typedef struct BdrvCoUnrefChild {
    Coroutine *co;
    
    BlockDriverState *parent;
    BdrvChild *child;
} BdrvCoUnrefChild;

static void bdrv_unref_child_bh(void *opaque)
{
    BdrvCoUnrefChild *s = opaque;

    bdrv_graph_wrlock();
    bdrv_unref_child(s->parent, s->child);
    bdrv_graph_wrunlock();

    aio_co_wake(s->co);
}

void coroutine_fn bdrv_co_unref_child(BlockDriverState *parent, BdrvChild *child)
{
    BdrvCoUnrefChild s = {
        .co = qemu_coroutine_self(),
        .parent = parent,
        .child = child,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), bdrv_unref_child_bh, &s);
    qemu_coroutine_yield();

    
}



/*
 * Wrappers for blk_new_with_bs
 */

typedef struct BlkCoNewWithBs {
    Coroutine *co;
    BlockBackend * ret;
    BlockDriverState *bs;
    uint64_t perm;
    uint64_t shared_perm;
    Error **errp;
} BlkCoNewWithBs;

static void blk_new_with_bs_bh(void *opaque)
{
    BlkCoNewWithBs *s = opaque;


    s->ret = blk_new_with_bs(s->bs, s->perm, s->shared_perm, s->errp);


    aio_co_wake(s->co);
}

BlockBackend * coroutine_fn blk_co_new_with_bs(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, Error **errp)
{
    BlkCoNewWithBs s = {
        .co = qemu_coroutine_self(),
        .bs = bs,
        .perm = perm,
        .shared_perm = shared_perm,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_new_with_bs_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for blk_new_open
 */

typedef struct BlkCoNewOpen {
    Coroutine *co;
    BlockBackend * ret;
    const char *filename;
    const char *reference;
    QDict *options;
    int flags;
    Error **errp;
} BlkCoNewOpen;

static void blk_new_open_bh(void *opaque)
{
    BlkCoNewOpen *s = opaque;


    s->ret = blk_new_open(s->filename, s->reference, s->options, s->flags, s->errp);


    aio_co_wake(s->co);
}

BlockBackend * coroutine_fn blk_co_new_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp)
{
    BlkCoNewOpen s = {
        .co = qemu_coroutine_self(),
        .filename = filename,
        .reference = reference,
        .options = options,
        .flags = flags,
        .errp = errp,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_new_open_bh, &s);
    qemu_coroutine_yield();

    return s.ret;
}


/*
 * Wrappers for blk_unref
 */

typedef struct BlkCoUnref {
    Coroutine *co;
    
    BlockBackend *blk;
} BlkCoUnref;

static void blk_unref_bh(void *opaque)
{
    BlkCoUnref *s = opaque;


    blk_unref(s->blk);


    aio_co_wake(s->co);
}

void coroutine_fn blk_co_unref(BlockBackend *blk)
{
    BlkCoUnref s = {
        .co = qemu_coroutine_self(),
        .blk = blk,
    };
    assert(qemu_in_coroutine());

    aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_unref_bh, &s);
    qemu_coroutine_yield();

    
}



/*
 * Wrappers for blk_co_is_inserted
 */

typedef struct BlkIsInserted {
    BdrvPollCo poll_state;
    bool ret;
    BlockBackend *blk;
} BlkIsInserted;

static void coroutine_fn blk_co_is_inserted_entry(void *opaque)
{
    BlkIsInserted *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = blk_co_is_inserted(s->blk);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

bool blk_is_inserted(BlockBackend *blk)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return blk_co_is_inserted(blk);
    } else {
        BlkIsInserted s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_is_inserted_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_is_available
 */

typedef struct BlkIsAvailable {
    BdrvPollCo poll_state;
    bool ret;
    BlockBackend *blk;
} BlkIsAvailable;

static void coroutine_fn blk_co_is_available_entry(void *opaque)
{
    BlkIsAvailable *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = blk_co_is_available(s->blk);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

bool blk_is_available(BlockBackend *blk)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return blk_co_is_available(blk);
    } else {
        BlkIsAvailable s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_is_available_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_lock_medium
 */

typedef struct BlkLockMedium {
    BdrvPollCo poll_state;
    
    BlockBackend *blk;
    bool locked;
} BlkLockMedium;

static void coroutine_fn blk_co_lock_medium_entry(void *opaque)
{
    BlkLockMedium *s = opaque;


    blk_co_lock_medium(s->blk, s->locked);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

void blk_lock_medium(BlockBackend *blk, bool locked)
{
    BlkLockMedium s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .blk = blk,
        .locked = locked,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(blk_co_lock_medium_entry, &s);

    bdrv_poll_co(&s.poll_state);
    
}


/*
 * Wrappers for blk_co_eject
 */

typedef struct BlkEject {
    BdrvPollCo poll_state;
    
    BlockBackend *blk;
    bool eject_flag;
} BlkEject;

static void coroutine_fn blk_co_eject_entry(void *opaque)
{
    BlkEject *s = opaque;


    blk_co_eject(s->blk, s->eject_flag);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

void blk_eject(BlockBackend *blk, bool eject_flag)
{
    BlkEject s = {
        .poll_state.ctx = qemu_get_current_aio_context(),
        .poll_state.in_progress = true,

        .blk = blk,
        .eject_flag = eject_flag,
    };
    assert(!qemu_in_coroutine());

    s.poll_state.co = qemu_coroutine_create(blk_co_eject_entry, &s);

    bdrv_poll_co(&s.poll_state);
    
}


/*
 * Wrappers for blk_co_getlength
 */

typedef struct BlkGetlength {
    BdrvPollCo poll_state;
    int64_t ret;
    BlockBackend *blk;
} BlkGetlength;

static void coroutine_fn blk_co_getlength_entry(void *opaque)
{
    BlkGetlength *s = opaque;


    s->ret = blk_co_getlength(s->blk);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int64_t blk_getlength(BlockBackend *blk)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_getlength(blk);
    } else {
        BlkGetlength s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_getlength_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pread
 */

typedef struct BlkPread {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    void *buf;
    BdrvRequestFlags flags;
} BlkPread;

static void coroutine_fn blk_co_pread_entry(void *opaque)
{
    BlkPread *s = opaque;


    s->ret = blk_co_pread(s->blk, s->offset, s->bytes, s->buf, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pread(BlockBackend *blk, int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pread(blk, offset, bytes, buf, flags);
    } else {
        BlkPread s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pread_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_preadv
 */

typedef struct BlkPreadv {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    QEMUIOVector *qiov;
    BdrvRequestFlags flags;
} BlkPreadv;

static void coroutine_fn blk_co_preadv_entry(void *opaque)
{
    BlkPreadv *s = opaque;


    s->ret = blk_co_preadv(s->blk, s->offset, s->bytes, s->qiov, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_preadv(blk, offset, bytes, qiov, flags);
    } else {
        BlkPreadv s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .qiov = qiov,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_preadv_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_preadv_part
 */

typedef struct BlkPreadvPart {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    QEMUIOVector *qiov;
    size_t qiov_offset;
    BdrvRequestFlags flags;
} BlkPreadvPart;

static void coroutine_fn blk_co_preadv_part_entry(void *opaque)
{
    BlkPreadvPart *s = opaque;


    s->ret = blk_co_preadv_part(s->blk, s->offset, s->bytes, s->qiov, s->qiov_offset, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_preadv_part(blk, offset, bytes, qiov, qiov_offset, flags);
    } else {
        BlkPreadvPart s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .qiov = qiov,
            .qiov_offset = qiov_offset,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_preadv_part_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pwrite
 */

typedef struct BlkPwrite {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    const void *buf;
    BdrvRequestFlags flags;
} BlkPwrite;

static void coroutine_fn blk_co_pwrite_entry(void *opaque)
{
    BlkPwrite *s = opaque;


    s->ret = blk_co_pwrite(s->blk, s->offset, s->bytes, s->buf, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pwrite(BlockBackend *blk, int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pwrite(blk, offset, bytes, buf, flags);
    } else {
        BlkPwrite s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pwrite_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pwritev
 */

typedef struct BlkPwritev {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    QEMUIOVector *qiov;
    BdrvRequestFlags flags;
} BlkPwritev;

static void coroutine_fn blk_co_pwritev_entry(void *opaque)
{
    BlkPwritev *s = opaque;


    s->ret = blk_co_pwritev(s->blk, s->offset, s->bytes, s->qiov, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pwritev(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pwritev(blk, offset, bytes, qiov, flags);
    } else {
        BlkPwritev s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .qiov = qiov,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pwritev_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pwritev_part
 */

typedef struct BlkPwritevPart {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    QEMUIOVector *qiov;
    size_t qiov_offset;
    BdrvRequestFlags flags;
} BlkPwritevPart;

static void coroutine_fn blk_co_pwritev_part_entry(void *opaque)
{
    BlkPwritevPart *s = opaque;


    s->ret = blk_co_pwritev_part(s->blk, s->offset, s->bytes, s->qiov, s->qiov_offset, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
    } else {
        BlkPwritevPart s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .qiov = qiov,
            .qiov_offset = qiov_offset,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pwritev_part_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pwrite_compressed
 */

typedef struct BlkPwriteCompressed {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    const void *buf;
} BlkPwriteCompressed;

static void coroutine_fn blk_co_pwrite_compressed_entry(void *opaque)
{
    BlkPwriteCompressed *s = opaque;


    s->ret = blk_co_pwrite_compressed(s->blk, s->offset, s->bytes, s->buf);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, int64_t bytes, const void *buf)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pwrite_compressed(blk, offset, bytes, buf);
    } else {
        BlkPwriteCompressed s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .buf = buf,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pwrite_compressed_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pwrite_zeroes
 */

typedef struct BlkPwriteZeroes {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
    BdrvRequestFlags flags;
} BlkPwriteZeroes;

static void coroutine_fn blk_co_pwrite_zeroes_entry(void *opaque)
{
    BlkPwriteZeroes *s = opaque;


    s->ret = blk_co_pwrite_zeroes(s->blk, s->offset, s->bytes, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, int64_t bytes, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pwrite_zeroes(blk, offset, bytes, flags);
    } else {
        BlkPwriteZeroes s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pwrite_zeroes_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_zone_report
 */

typedef struct BlkZoneReport {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    unsigned int *nr_zones;
    BlockZoneDescriptor *zones;
} BlkZoneReport;

static void coroutine_fn blk_co_zone_report_entry(void *opaque)
{
    BlkZoneReport *s = opaque;


    s->ret = blk_co_zone_report(s->blk, s->offset, s->nr_zones, s->zones);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_zone_report(BlockBackend *blk, int64_t offset, unsigned int *nr_zones, BlockZoneDescriptor *zones)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_zone_report(blk, offset, nr_zones, zones);
    } else {
        BlkZoneReport s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .nr_zones = nr_zones,
            .zones = zones,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_zone_report_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_zone_mgmt
 */

typedef struct BlkZoneMgmt {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    BlockZoneOp op;
    int64_t offset;
    int64_t len;
} BlkZoneMgmt;

static void coroutine_fn blk_co_zone_mgmt_entry(void *opaque)
{
    BlkZoneMgmt *s = opaque;


    s->ret = blk_co_zone_mgmt(s->blk, s->op, s->offset, s->len);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_zone_mgmt(BlockBackend *blk, BlockZoneOp op, int64_t offset, int64_t len)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_zone_mgmt(blk, op, offset, len);
    } else {
        BlkZoneMgmt s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .op = op,
            .offset = offset,
            .len = len,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_zone_mgmt_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_zone_append
 */

typedef struct BlkZoneAppend {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t *offset;
    QEMUIOVector *qiov;
    BdrvRequestFlags flags;
} BlkZoneAppend;

static void coroutine_fn blk_co_zone_append_entry(void *opaque)
{
    BlkZoneAppend *s = opaque;


    s->ret = blk_co_zone_append(s->blk, s->offset, s->qiov, s->flags);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_zone_append(BlockBackend *blk, int64_t *offset, QEMUIOVector *qiov, BdrvRequestFlags flags)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_zone_append(blk, offset, qiov, flags);
    } else {
        BlkZoneAppend s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .qiov = qiov,
            .flags = flags,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_zone_append_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_pdiscard
 */

typedef struct BlkPdiscard {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    int64_t bytes;
} BlkPdiscard;

static void coroutine_fn blk_co_pdiscard_entry(void *opaque)
{
    BlkPdiscard *s = opaque;


    s->ret = blk_co_pdiscard(s->blk, s->offset, s->bytes);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_pdiscard(blk, offset, bytes);
    } else {
        BlkPdiscard s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .bytes = bytes,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_pdiscard_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_flush
 */

typedef struct BlkFlush {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
} BlkFlush;

static void coroutine_fn blk_co_flush_entry(void *opaque)
{
    BlkFlush *s = opaque;


    s->ret = blk_co_flush(s->blk);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_flush(BlockBackend *blk)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_flush(blk);
    } else {
        BlkFlush s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_flush_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_ioctl
 */

typedef struct BlkIoctl {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    unsigned long int req;
    void *buf;
} BlkIoctl;

static void coroutine_fn blk_co_ioctl_entry(void *opaque)
{
    BlkIoctl *s = opaque;


    s->ret = blk_co_ioctl(s->blk, s->req, s->buf);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_ioctl(blk, req, buf);
    } else {
        BlkIoctl s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .req = req,
            .buf = buf,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_ioctl_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for blk_co_truncate
 */

typedef struct BlkTruncate {
    BdrvPollCo poll_state;
    int ret;
    BlockBackend *blk;
    int64_t offset;
    bool exact;
    PreallocMode prealloc;
    BdrvRequestFlags flags;
    Error **errp;
} BlkTruncate;

static void coroutine_fn blk_co_truncate_entry(void *opaque)
{
    BlkTruncate *s = opaque;


    s->ret = blk_co_truncate(s->blk, s->offset, s->exact, s->prealloc, s->flags, s->errp);

    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
    if (qemu_in_coroutine()) {
        
        return blk_co_truncate(blk, offset, exact, prealloc, flags, errp);
    } else {
        BlkTruncate s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .blk = blk,
            .offset = offset,
            .exact = exact,
            .prealloc = prealloc,
            .flags = flags,
            .errp = errp,
        };

        s.poll_state.co = qemu_coroutine_create(blk_co_truncate_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}



/*
 * Wrappers for bdrv_co_common_block_status_above
 */

typedef struct BdrvCommonBlockStatusAbove {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    BlockDriverState *base;
    bool include_base;
    unsigned int mode;
    int64_t offset;
    int64_t bytes;
    int64_t *pnum;
    int64_t *map;
    BlockDriverState **file;
    int *depth;
} BdrvCommonBlockStatusAbove;

static void coroutine_fn bdrv_co_common_block_status_above_entry(void *opaque)
{
    BdrvCommonBlockStatusAbove *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = bdrv_co_common_block_status_above(s->bs, s->base, s->include_base, s->mode, s->offset, s->bytes, s->pnum, s->map, s->file, s->depth);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int bdrv_common_block_status_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file, int *depth)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return bdrv_co_common_block_status_above(bs, base, include_base, mode, offset, bytes, pnum, map, file, depth);
    } else {
        BdrvCommonBlockStatusAbove s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .base = base,
            .include_base = include_base,
            .mode = mode,
            .offset = offset,
            .bytes = bytes,
            .pnum = pnum,
            .map = map,
            .file = file,
            .depth = depth,
        };

        s.poll_state.co = qemu_coroutine_create(bdrv_co_common_block_status_above_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}


/*
 * Wrappers for nbd_co_do_establish_connection
 */

typedef struct NbdDoEstablishConnection {
    BdrvPollCo poll_state;
    int ret;
    BlockDriverState *bs;
    bool blocking;
    Error **errp;
} NbdDoEstablishConnection;

static void coroutine_fn nbd_co_do_establish_connection_entry(void *opaque)
{
    NbdDoEstablishConnection *s = opaque;

    bdrv_graph_co_rdlock();
    s->ret = nbd_co_do_establish_connection(s->bs, s->blocking, s->errp);
    bdrv_graph_co_rdunlock();
    s->poll_state.in_progress = false;

    aio_wait_kick();
}

int nbd_do_establish_connection(BlockDriverState *bs, bool blocking, Error **errp)
{
    if (qemu_in_coroutine()) {
        assume_graph_lock();
        return nbd_co_do_establish_connection(bs, blocking, errp);
    } else {
        NbdDoEstablishConnection s = {
            .poll_state.ctx = qemu_get_current_aio_context(),
            .poll_state.in_progress = true,

            .bs = bs,
            .blocking = blocking,
            .errp = errp,
        };

        s.poll_state.co = qemu_coroutine_create(nbd_co_do_establish_connection_entry, &s);

        bdrv_poll_co(&s.poll_state);
        return s.ret;
    }
}
