Makefile | 8 + block/block-gen.h | 55 ++++ block/coroutines.h | 66 +++++ include/block/block.h | 25 +- include/block/generated-co-wrapper.h | 35 +++ block.c | 97 +------ block/io.c | 383 ++++----------------------- tests/test-bdrv-drain.c | 2 +- block/Makefile.objs | 1 + scripts/coroutine-wrapper.py | 173 ++++++++++++ 10 files changed, 417 insertions(+), 428 deletions(-) create mode 100644 block/block-gen.h create mode 100644 block/coroutines.h create mode 100644 include/block/generated-co-wrapper.h create mode 100755 scripts/coroutine-wrapper.py
Hi all!
The aim of the series is to reduce code-duplication and writing
parameters structure-packing by hand around coroutine function wrappers.
It's an alternative to "[PATCH v3] block: Factor out bdrv_run_co()"
patch.
Benefits:
- no code duplication
- less indirection
v5: mostly by Eric's suggestions:
01: new
02: tweak commit message
03: - fix type in commit message
- rebase on 01
- keep Eric's r-b
04: - conversion splitted to 05
- script mostly rewritten
- use f-strings for templating
- add copyright to generated file header
- wrap long lines if clang-format available
- fix makefiles
05: splitted from 04 mechanical conversion
06: tweak commit message, add Eric's r-b
07: add Eric's r-b
For convenience I attach generated block/block-gen.c file below.
Vladimir Sementsov-Ogievskiy (7):
block: return error-code from bdrv_invalidate_cache
block/io: refactor coroutine wrappers
block: declare some coroutine functions in block/coroutines.h
scripts: add coroutine-wrapper.py
block: generate coroutine-wrapper code
block: drop bdrv_prwv
block/io: refactor save/load vmstate
Makefile | 8 +
block/block-gen.h | 55 ++++
block/coroutines.h | 66 +++++
include/block/block.h | 25 +-
include/block/generated-co-wrapper.h | 35 +++
block.c | 97 +------
block/io.c | 383 ++++-----------------------
tests/test-bdrv-drain.c | 2 +-
block/Makefile.objs | 1 +
scripts/coroutine-wrapper.py | 173 ++++++++++++
10 files changed, 417 insertions(+), 428 deletions(-)
create mode 100644 block/block-gen.h
create mode 100644 block/coroutines.h
create mode 100644 include/block/generated-co-wrapper.h
create mode 100755 scripts/coroutine-wrapper.py
===== Generated block/block-gen.c ======
/*
* File is generated by scripts/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"
/*
* Wrappers for bdrv_co_truncate
*/
typedef struct BdrvCoTruncate {
BdrvPollCo poll_state;
BdrvChild *child;
int64_t offset;
bool exact;
PreallocMode prealloc;
BdrvRequestFlags flags;
Error **errp;
} BdrvCoTruncate;
static void coroutine_fn bdrv_co_truncate_entry(void *opaque)
{
BdrvCoTruncate *s = opaque;
s->poll_state.ret = bdrv_co_truncate(s->child, s->offset, s->exact,
s->prealloc, s->flags, s->errp);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{
if (qemu_in_coroutine()) {
return bdrv_co_truncate(child, offset, exact, prealloc, flags, errp);
} else {
BdrvCoTruncate s = {
.poll_state.bs = child->bs,
.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);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_check
*/
typedef struct BdrvCoCheck {
BdrvPollCo poll_state;
BlockDriverState *bs;
BdrvCheckResult *res;
BdrvCheckMode fix;
} BdrvCoCheck;
static void coroutine_fn bdrv_co_check_entry(void *opaque)
{
BdrvCoCheck *s = opaque;
s->poll_state.ret = bdrv_co_check(s->bs, s->res, s->fix);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
if (qemu_in_coroutine()) {
return bdrv_co_check(bs, res, fix);
} else {
BdrvCoCheck s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
.res = res,
.fix = fix,
};
s.poll_state.co = qemu_coroutine_create(bdrv_co_check_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_invalidate_cache
*/
typedef struct BdrvCoInvalidateCache {
BdrvPollCo poll_state;
BlockDriverState *bs;
Error **errp;
} BdrvCoInvalidateCache;
static void coroutine_fn bdrv_co_invalidate_cache_entry(void *opaque)
{
BdrvCoInvalidateCache *s = opaque;
s->poll_state.ret = bdrv_co_invalidate_cache(s->bs, s->errp);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
{
if (qemu_in_coroutine()) {
return bdrv_co_invalidate_cache(bs, errp);
} else {
BdrvCoInvalidateCache s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
.errp = errp,
};
s.poll_state.co =
qemu_coroutine_create(bdrv_co_invalidate_cache_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_flush
*/
typedef struct BdrvCoFlush {
BdrvPollCo poll_state;
BlockDriverState *bs;
} BdrvCoFlush;
static void coroutine_fn bdrv_co_flush_entry(void *opaque)
{
BdrvCoFlush *s = opaque;
s->poll_state.ret = bdrv_co_flush(s->bs);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_flush(BlockDriverState *bs)
{
if (qemu_in_coroutine()) {
return bdrv_co_flush(bs);
} else {
BdrvCoFlush s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
};
s.poll_state.co = qemu_coroutine_create(bdrv_co_flush_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_pdiscard
*/
typedef struct BdrvCoPdiscard {
BdrvPollCo poll_state;
BdrvChild *child;
int64_t offset;
int64_t bytes;
} BdrvCoPdiscard;
static void coroutine_fn bdrv_co_pdiscard_entry(void *opaque)
{
BdrvCoPdiscard *s = opaque;
s->poll_state.ret = bdrv_co_pdiscard(s->child, s->offset, s->bytes);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
{
if (qemu_in_coroutine()) {
return bdrv_co_pdiscard(child, offset, bytes);
} else {
BdrvCoPdiscard s = {
.poll_state.bs = child->bs,
.poll_state.in_progress = true,
.child = child,
.offset = offset,
.bytes = bytes,
};
s.poll_state.co = qemu_coroutine_create(bdrv_co_pdiscard_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_readv_vmstate
*/
typedef struct BdrvCoReadvVmstate {
BdrvPollCo poll_state;
BlockDriverState *bs;
QEMUIOVector *qiov;
int64_t pos;
} BdrvCoReadvVmstate;
static void coroutine_fn bdrv_co_readv_vmstate_entry(void *opaque)
{
BdrvCoReadvVmstate *s = opaque;
s->poll_state.ret = bdrv_co_readv_vmstate(s->bs, s->qiov, s->pos);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{
if (qemu_in_coroutine()) {
return bdrv_co_readv_vmstate(bs, qiov, pos);
} else {
BdrvCoReadvVmstate s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
.qiov = qiov,
.pos = pos,
};
s.poll_state.co =
qemu_coroutine_create(bdrv_co_readv_vmstate_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_writev_vmstate
*/
typedef struct BdrvCoWritevVmstate {
BdrvPollCo poll_state;
BlockDriverState *bs;
QEMUIOVector *qiov;
int64_t pos;
} BdrvCoWritevVmstate;
static void coroutine_fn bdrv_co_writev_vmstate_entry(void *opaque)
{
BdrvCoWritevVmstate *s = opaque;
s->poll_state.ret = bdrv_co_writev_vmstate(s->bs, s->qiov, s->pos);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{
if (qemu_in_coroutine()) {
return bdrv_co_writev_vmstate(bs, qiov, pos);
} else {
BdrvCoWritevVmstate s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
.qiov = qiov,
.pos = pos,
};
s.poll_state.co =
qemu_coroutine_create(bdrv_co_writev_vmstate_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_preadv
*/
typedef struct BdrvCoPreadv {
BdrvPollCo poll_state;
BdrvChild *child;
int64_t offset;
unsigned int bytes;
QEMUIOVector *qiov;
BdrvRequestFlags flags;
} BdrvCoPreadv;
static void coroutine_fn bdrv_co_preadv_entry(void *opaque)
{
BdrvCoPreadv *s = opaque;
s->poll_state.ret =
bdrv_co_preadv(s->child, s->offset, s->bytes, s->qiov, s->flags);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_preadv(BdrvChild *child, int64_t offset, unsigned int bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
if (qemu_in_coroutine()) {
return bdrv_co_preadv(child, offset, bytes, qiov, flags);
} else {
BdrvCoPreadv s = {
.poll_state.bs = child->bs,
.poll_state.in_progress = true,
.child = child,
.offset = offset,
.bytes = bytes,
.qiov = qiov,
.flags = flags,
};
s.poll_state.co = qemu_coroutine_create(bdrv_co_preadv_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_pwritev
*/
typedef struct BdrvCoPwritev {
BdrvPollCo poll_state;
BdrvChild *child;
int64_t offset;
unsigned int bytes;
QEMUIOVector *qiov;
BdrvRequestFlags flags;
} BdrvCoPwritev;
static void coroutine_fn bdrv_co_pwritev_entry(void *opaque)
{
BdrvCoPwritev *s = opaque;
s->poll_state.ret =
bdrv_co_pwritev(s->child, s->offset, s->bytes, s->qiov, s->flags);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
if (qemu_in_coroutine()) {
return bdrv_co_pwritev(child, offset, bytes, qiov, flags);
} else {
BdrvCoPwritev s = {
.poll_state.bs = child->bs,
.poll_state.in_progress = true,
.child = child,
.offset = offset,
.bytes = bytes,
.qiov = qiov,
.flags = flags,
};
s.poll_state.co = qemu_coroutine_create(bdrv_co_pwritev_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
/*
* Wrappers for bdrv_co_common_block_status_above
*/
typedef struct BdrvCoCommonBlockStatusAbove {
BdrvPollCo poll_state;
BlockDriverState *bs;
BlockDriverState *base;
bool want_zero;
int64_t offset;
int64_t bytes;
int64_t *pnum;
int64_t *map;
BlockDriverState **file;
} BdrvCoCommonBlockStatusAbove;
static void coroutine_fn bdrv_co_common_block_status_above_entry(void *opaque)
{
BdrvCoCommonBlockStatusAbove *s = opaque;
s->poll_state.ret = bdrv_co_common_block_status_above(
s->bs, s->base, s->want_zero, s->offset, s->bytes, s->pnum, s->map,
s->file);
s->poll_state.in_progress = false;
bdrv_poll_co__on_exit();
}
int bdrv_common_block_status_above(BlockDriverState *bs, BlockDriverState *base,
bool want_zero, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map,
BlockDriverState **file)
{
if (qemu_in_coroutine()) {
return bdrv_co_common_block_status_above(bs, base, want_zero, offset,
bytes, pnum, map, file);
} else {
BdrvCoCommonBlockStatusAbove s = {
.poll_state.bs = bs,
.poll_state.in_progress = true,
.bs = bs,
.base = base,
.want_zero = want_zero,
.offset = offset,
.bytes = bytes,
.pnum = pnum,
.map = map,
.file = file,
};
s.poll_state.co =
qemu_coroutine_create(bdrv_co_common_block_status_above_entry, &s);
return bdrv_poll_co(&s.poll_state);
}
}
========================================
--
2.21.0
Patchew URL: https://patchew.org/QEMU/20200527203733.16129-1-vsementsov@virtuozzo.com/
Hi,
This series failed the docker-quick@centos7 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.
=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===
TypeError: __init__() got an unexpected keyword argument 'capture_output'
CC /tmp/qemu-test/build/slirp/src/bootp.o
GEN ui/input-keymap-usb-to-qcode.c
make: *** [block/block-gen.c] Error 1
make: *** Deleting file `block/block-gen.c'
make: *** Waiting for unfinished jobs....
GEN ui/input-keymap-win32-to-qcode.c
---
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=7a4c9c87bb7b4b61ae99142b8ccd4c12', '-u', '1001', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-vw5w7k6z/src/docker-src.2020-05-27-17.44.40.573:/var/tmp/qemu:z,ro', 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2.
filter=--filter=label=com.qemu.instance.uuid=7a4c9c87bb7b4b61ae99142b8ccd4c12
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-vw5w7k6z/src'
make: *** [docker-run-test-quick@centos7] Error 2
real 1m57.906s
user 0m8.475s
The full log is available at
http://patchew.org/logs/20200527203733.16129-1-vsementsov@virtuozzo.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com
On 5/27/20 4:46 PM, no-reply@patchew.org wrote:
> Patchew URL: https://patchew.org/QEMU/20200527203733.16129-1-vsementsov@virtuozzo.com/
>
>
>
> Hi,
>
> This series failed the docker-quick@centos7 build test. Please find the testing commands and
> their output below. If you have Docker installed, you can probably reproduce it
> locally.
>
> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> make docker-image-centos7 V=1 NETWORK=1
> time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
> === TEST SCRIPT END ===
>
> TypeError: __init__() got an unexpected keyword argument 'capture_output'
> CC /tmp/qemu-test/build/slirp/src/bootp.o
> GEN ui/input-keymap-usb-to-qcode.c
> make: *** [block/block-gen.c] Error 1
> make: *** Deleting file `block/block-gen.c'
> make: *** Waiting for unfinished jobs....
> GEN ui/input-keymap-win32-to-qcode.c
The more interesting part of the failure:
File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 173, in
<module>
print(gen_wrappers_file(sys.stdin.read()))
File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 169, in
gen_wrappers_file
return prettify(res) # prettify to wrap long lines
File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 40, in
prettify
encoding='utf-8', input=code, capture_output=True)
File "/usr/lib64/python3.6/subprocess.py", line 423, in run
with Popen(*popenargs, **kwargs) as process:
TypeError: __init__() got an unexpected keyword argument 'capture_output'
which indeed looks like a bug in the patch.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
28.05.2020 00:57, Eric Blake wrote: > On 5/27/20 4:46 PM, no-reply@patchew.org wrote: >> Patchew URL: https://patchew.org/QEMU/20200527203733.16129-1-vsementsov@virtuozzo.com/ >> >> >> >> Hi, >> >> This series failed the docker-quick@centos7 build test. Please find the testing commands and >> their output below. If you have Docker installed, you can probably reproduce it >> locally. >> >> === TEST SCRIPT BEGIN === >> #!/bin/bash >> make docker-image-centos7 V=1 NETWORK=1 >> time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1 >> === TEST SCRIPT END === >> >> TypeError: __init__() got an unexpected keyword argument 'capture_output' >> CC /tmp/qemu-test/build/slirp/src/bootp.o >> GEN ui/input-keymap-usb-to-qcode.c >> make: *** [block/block-gen.c] Error 1 >> make: *** Deleting file `block/block-gen.c' >> make: *** Waiting for unfinished jobs.... >> GEN ui/input-keymap-win32-to-qcode.c > > The more interesting part of the failure: > > File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 173, in <module> > print(gen_wrappers_file(sys.stdin.read())) > File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 169, in gen_wrappers_file > return prettify(res) # prettify to wrap long lines > File "/tmp/qemu-test/src/scripts/coroutine-wrapper.py", line 40, in prettify > encoding='utf-8', input=code, capture_output=True) > File "/usr/lib64/python3.6/subprocess.py", line 423, in run > with Popen(*popenargs, **kwargs) as process: > TypeError: __init__() got an unexpected keyword argument 'capture_output' > > which indeed looks like a bug in the patch. > Ah, yes, capture_output is since python 3.7. So, s/capture_output=True/stdout=subprocess.PIPE/ . -- Best regards, Vladimir
Patchew URL: https://patchew.org/QEMU/20200527203733.16129-1-vsementsov@virtuozzo.com/
Hi,
This series failed the docker-quick@centos7 build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.
=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
=== TEST SCRIPT END ===
with Popen(*popenargs, **kwargs) as process:
TypeError: __init__() got an unexpected keyword argument 'capture_output'
CC /tmp/qemu-test/build/slirp/src/arp_table.o
make: *** [block/block-gen.c] Error 1
make: *** Deleting file `block/block-gen.c'
CC /tmp/qemu-test/build/slirp/src/util.o
make: *** Waiting for unfinished jobs....
---
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=e9801db6c81946b8b7007cd3179a6d18', '-u', '1003', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew2/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-eja8hzsv/src/docker-src.2020-05-27-18.23.44.9751:/var/tmp/qemu:z,ro', 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2.
filter=--filter=label=com.qemu.instance.uuid=e9801db6c81946b8b7007cd3179a6d18
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-eja8hzsv/src'
make: *** [docker-run-test-quick@centos7] Error 2
real 2m1.393s
user 0m7.847s
The full log is available at
http://patchew.org/logs/20200527203733.16129-1-vsementsov@virtuozzo.com/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com
© 2016 - 2026 Red Hat, Inc.