Block layer patches

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJXNIcBAAoJEH8JsnLIjy/WiUQP/Rzfo8pe7TWA2InxdcDOPsx4
 2/tHHJdVkffnNX5rdBvc0mOUZNJxej0NtJu2e63BB+ydYju//xw8gruKU7TR+Nd3
 nPNSsqk80prK3RNgWu7qymBvIkHDDcDQhlp48HKq+dxrfConXtHmoXapGsqc0S47
 xu03oC6WzSIyLf7TLytcjUmEprQSaCGOwsb/XaHAWL750fFAGcdy/K5PWBpUv6DN
 T0jZ3u4UneE1jeabRmqAwjgDJXC9l6riH9fP/ZtYhgNlNj84zlMXajUHSULhGknP
 cTGjwwg9tOvhcjTdhdRmWlvG1m0T77ZX3icfZLhcTdb/Uz68NXVqs8P25IGV9McD
 DPrb3T/M8JUoqLXJxIpxUm2Levof5v0dUF1PHmN5bT7pshcqv/1J7v8Fdtf9l9mp
 zI0+FK1TZ102C0H2F7AWYZSlo2EfNUSd02QQx6MbfDokDIlIxY+EgP1/Es5XlkqC
 wc7HrJvq+uix2zXw9bn9Vg9p/nDuxlRx+ppRRarNNRonaqTrx/1qAaas4bsqc9Gz
 H6gxw7BHybm0TZFdHqAdIonpesecYw6yWUXT/mQehbfphsmQmu/d2HvF2C9uUm4X
 O0JduBlKOTm2hMcg5qL6Gko8WaQIctdCJH/1Onts92cZnm8Vr/9zcmMgwGoCd7sE
 +t6Yg0jqpTUJwhZhIuCw
 =NbjJ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches

# gpg: Signature made Thu 12 May 2016 14:37:05 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (69 commits)
  qemu-iotests: iotests: fail hard if not run via "check"
  block: enable testing of LUKS driver with block I/O tests
  block: add support for encryption secrets in block I/O tests
  block: add support for --image-opts in block I/O tests
  qemu-io: Add 'write -z -u' to test MAY_UNMAP flag
  qemu-io: Add 'write -f' to test FUA flag
  qemu-io: Allow unaligned access by default
  qemu-io: Use bool for command line flags
  qemu-io: Make 'open' subcommand more like command line
  qemu-io: Add missing option documentation
  qmp: add monitor command to add/remove a child
  quorum: implement bdrv_add_child() and bdrv_del_child()
  Add new block driver interface to add/delete a BDS's child
  qemu-img: check block status of backing file when converting.
  iotests: fix the redirection order in 083
  block: Inactivate all children
  block: Drop superfluous invalidating bs->file from drivers
  block: Invalidate all children
  nbd: Simplify client FUA handling
  block: Honor BDRV_REQ_FUA during write_zeroes
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-05-12 16:33:40 +01:00
commit f68419eee9
78 changed files with 3335 additions and 2071 deletions

127
block.c
View File

@ -218,8 +218,6 @@ void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
void bdrv_register(BlockDriver *bdrv) void bdrv_register(BlockDriver *bdrv)
{ {
bdrv_setup_io_funcs(bdrv);
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list); QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
} }
@ -1176,10 +1174,10 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
return child; return child;
} }
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs, BlockDriverState *child_bs,
const char *child_name, const char *child_name,
const BdrvChildRole *child_role) const BdrvChildRole *child_role)
{ {
BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role); BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role);
QLIST_INSERT_HEAD(&parent_bs->children, child, next); QLIST_INSERT_HEAD(&parent_bs->children, child, next);
@ -2261,7 +2259,6 @@ static void swap_feature_fields(BlockDriverState *bs_top,
assert(!bs_new->throttle_state); assert(!bs_new->throttle_state);
if (bs_top->throttle_state) { if (bs_top->throttle_state) {
assert(bs_top->io_limits_enabled);
bdrv_io_limits_enable(bs_new, throttle_group_get_name(bs_top)); bdrv_io_limits_enable(bs_new, throttle_group_get_name(bs_top));
bdrv_io_limits_disable(bs_top); bdrv_io_limits_disable(bs_top);
} }
@ -3201,6 +3198,7 @@ void bdrv_init_with_whitelist(void)
void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
{ {
BdrvChild *child;
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
@ -3215,13 +3213,20 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
if (bs->drv->bdrv_invalidate_cache) { if (bs->drv->bdrv_invalidate_cache) {
bs->drv->bdrv_invalidate_cache(bs, &local_err); bs->drv->bdrv_invalidate_cache(bs, &local_err);
} else if (bs->file) { if (local_err) {
bdrv_invalidate_cache(bs->file->bs, &local_err); bs->open_flags |= BDRV_O_INACTIVE;
error_propagate(errp, local_err);
return;
}
} }
if (local_err) {
bs->open_flags |= BDRV_O_INACTIVE; QLIST_FOREACH(child, &bs->children, next) {
error_propagate(errp, local_err); bdrv_invalidate_cache(child->bs, &local_err);
return; if (local_err) {
bs->open_flags |= BDRV_O_INACTIVE;
error_propagate(errp, local_err);
return;
}
} }
ret = refresh_total_sectors(bs, bs->total_sectors); ret = refresh_total_sectors(bs, bs->total_sectors);
@ -3250,38 +3255,63 @@ void bdrv_invalidate_cache_all(Error **errp)
} }
} }
static int bdrv_inactivate(BlockDriverState *bs) static int bdrv_inactivate_recurse(BlockDriverState *bs,
bool setting_flag)
{ {
BdrvChild *child;
int ret; int ret;
if (bs->drv->bdrv_inactivate) { if (!setting_flag && bs->drv->bdrv_inactivate) {
ret = bs->drv->bdrv_inactivate(bs); ret = bs->drv->bdrv_inactivate(bs);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
} }
bs->open_flags |= BDRV_O_INACTIVE; QLIST_FOREACH(child, &bs->children, next) {
ret = bdrv_inactivate_recurse(child->bs, setting_flag);
if (ret < 0) {
return ret;
}
}
if (setting_flag) {
bs->open_flags |= BDRV_O_INACTIVE;
}
return 0; return 0;
} }
int bdrv_inactivate_all(void) int bdrv_inactivate_all(void)
{ {
BlockDriverState *bs = NULL; BlockDriverState *bs = NULL;
int ret; int ret = 0;
int pass;
while ((bs = bdrv_next(bs)) != NULL) { while ((bs = bdrv_next(bs)) != NULL) {
AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(bdrv_get_aio_context(bs));
}
aio_context_acquire(aio_context); /* We do two passes of inactivation. The first pass calls to drivers'
ret = bdrv_inactivate(bs); * .bdrv_inactivate callbacks recursively so all cache is flushed to disk;
aio_context_release(aio_context); * the second pass sets the BDRV_O_INACTIVE flag so that no further write
if (ret < 0) { * is allowed. */
return ret; for (pass = 0; pass < 2; pass++) {
bs = NULL;
while ((bs = bdrv_next(bs)) != NULL) {
ret = bdrv_inactivate_recurse(bs, pass);
if (ret < 0) {
goto out;
}
} }
} }
return 0; out:
bs = NULL;
while ((bs = bdrv_next(bs)) != NULL) {
aio_context_release(bdrv_get_aio_context(bs));
}
return ret;
} }
/**************************************************************/ /**************************************************************/
@ -3981,3 +4011,52 @@ void bdrv_refresh_filename(BlockDriverState *bs)
QDECREF(json); QDECREF(json);
} }
} }
/*
* Hot add/remove a BDS's child. So the user can take a child offline when
* it is broken and take a new child online
*/
void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs,
Error **errp)
{
if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) {
error_setg(errp, "The node %s does not support adding a child",
bdrv_get_device_or_node_name(parent_bs));
return;
}
if (!QLIST_EMPTY(&child_bs->parents)) {
error_setg(errp, "The node %s already has a parent",
child_bs->node_name);
return;
}
parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp);
}
void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
{
BdrvChild *tmp;
if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) {
error_setg(errp, "The node %s does not support removing a child",
bdrv_get_device_or_node_name(parent_bs));
return;
}
QLIST_FOREACH(tmp, &parent_bs->children, next) {
if (tmp == child) {
break;
}
}
if (!tmp) {
error_setg(errp, "The node %s does not have a child named %s",
bdrv_get_device_or_node_name(parent_bs),
bdrv_get_device_or_node_name(child->bs));
return;
}
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}

View File

@ -1,7 +1,7 @@
/* /*
* QEMU Block backends * QEMU Block backends
* *
* Copyright (C) 2014 Red Hat, Inc. * Copyright (C) 2014-2016 Red Hat, Inc.
* *
* Authors: * Authors:
* Markus Armbruster <armbru@redhat.com>, * Markus Armbruster <armbru@redhat.com>,
@ -692,7 +692,7 @@ static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
return ret; return ret;
} }
return bdrv_co_do_preadv(blk_bs(blk), offset, bytes, qiov, flags); return bdrv_co_preadv(blk_bs(blk), offset, bytes, qiov, flags);
} }
static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
@ -710,7 +710,7 @@ static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
flags |= BDRV_REQ_FUA; flags |= BDRV_REQ_FUA;
} }
return bdrv_co_do_pwritev(blk_bs(blk), offset, bytes, qiov, flags); return bdrv_co_pwritev(blk_bs(blk), offset, bytes, qiov, flags);
} }
typedef struct BlkRwCo { typedef struct BlkRwCo {
@ -772,55 +772,28 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
return rwco.ret; return rwco.ret;
} }
static int blk_rw(BlockBackend *blk, int64_t sector_num, uint8_t *buf, int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
int nb_sectors, CoroutineEntry co_entry, int count)
BdrvRequestFlags flags)
{
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
return -EINVAL;
}
return blk_prw(blk, sector_num << BDRV_SECTOR_BITS, buf,
nb_sectors << BDRV_SECTOR_BITS, co_entry, flags);
}
int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors)
{
return blk_rw(blk, sector_num, buf, nb_sectors, blk_read_entry, 0);
}
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors)
{ {
BlockDriverState *bs = blk_bs(blk); BlockDriverState *bs = blk_bs(blk);
bool enabled;
int ret; int ret;
ret = blk_check_request(blk, sector_num, nb_sectors); ret = blk_check_byte_request(blk, offset, count);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
enabled = bs->io_limits_enabled; bdrv_no_throttling_begin(bs);
bs->io_limits_enabled = false; ret = blk_pread(blk, offset, buf, count);
ret = blk_read(blk, sector_num, buf, nb_sectors); bdrv_no_throttling_end(bs);
bs->io_limits_enabled = enabled;
return ret; return ret;
} }
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf, int blk_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors) int count, BdrvRequestFlags flags)
{ {
return blk_rw(blk, sector_num, (uint8_t*) buf, nb_sectors, return blk_prw(blk, offset, NULL, count, blk_write_entry,
blk_write_entry, 0); flags | BDRV_REQ_ZERO_WRITE);
}
int blk_write_zeroes(BlockBackend *blk, int64_t sector_num,
int nb_sectors, BdrvRequestFlags flags)
{
return blk_rw(blk, sector_num, NULL, nb_sectors, blk_write_entry,
flags | BDRV_REQ_ZERO_WRITE);
} }
static void error_callback_bh(void *opaque) static void error_callback_bh(void *opaque)
@ -932,18 +905,12 @@ static void blk_aio_write_entry(void *opaque)
blk_aio_complete(acb); blk_aio_complete(acb);
} }
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num, BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors, BdrvRequestFlags flags, int count, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { return blk_aio_prwv(blk, offset, count, NULL, blk_aio_write_entry,
return blk_abort_aio_request(blk, cb, opaque, -EINVAL); flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
}
return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS,
nb_sectors << BDRV_SECTOR_BITS, NULL,
blk_aio_write_entry, flags | BDRV_REQ_ZERO_WRITE,
cb, opaque);
} }
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count) int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
@ -955,9 +922,11 @@ int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
return count; return count;
} }
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count) int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count,
BdrvRequestFlags flags)
{ {
int ret = blk_prw(blk, offset, (void*) buf, count, blk_write_entry, 0); int ret = blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
flags);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -991,30 +960,20 @@ int64_t blk_nb_sectors(BlockBackend *blk)
return bdrv_nb_sectors(blk_bs(blk)); return bdrv_nb_sectors(blk_bs(blk));
} }
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num, BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque)
{
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
return blk_abort_aio_request(blk, cb, opaque, -EINVAL);
}
assert(nb_sectors << BDRV_SECTOR_BITS == iov->size);
return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, iov->size, iov,
blk_aio_read_entry, 0, cb, opaque);
}
BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { return blk_aio_prwv(blk, offset, qiov->size, qiov,
return blk_abort_aio_request(blk, cb, opaque, -EINVAL); blk_aio_read_entry, flags, cb, opaque);
} }
assert(nb_sectors << BDRV_SECTOR_BITS == iov->size); BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, iov->size, iov, QEMUIOVector *qiov, BdrvRequestFlags flags,
blk_aio_write_entry, 0, cb, opaque); BlockCompletionFunc *cb, void *opaque)
{
return blk_aio_prwv(blk, offset, qiov->size, qiov,
blk_aio_write_entry, flags, cb, opaque);
} }
BlockAIOCB *blk_aio_flush(BlockBackend *blk, BlockAIOCB *blk_aio_flush(BlockBackend *blk,
@ -1444,15 +1403,10 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque); return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque);
} }
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num, int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors, BdrvRequestFlags flags) int count, BdrvRequestFlags flags)
{ {
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) { return blk_co_pwritev(blk, offset, count, NULL,
return -EINVAL;
}
return blk_co_pwritev(blk, sector_num << BDRV_SECTOR_BITS,
nb_sectors << BDRV_SECTOR_BITS, NULL,
flags | BDRV_REQ_ZERO_WRITE); flags | BDRV_REQ_ZERO_WRITE);
} }

View File

@ -104,6 +104,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
bs->read_only = 1; // no write support yet bs->read_only = 1; // no write support yet
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs)); ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs));
if (ret < 0) { if (ret < 0) {
@ -221,38 +222,52 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
} }
static int bochs_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) bochs_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVBochsState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
uint64_t bytes_done = 0;
QEMUIOVector local_qiov;
int ret; int ret;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
qemu_iovec_init(&local_qiov, qiov->niov);
qemu_co_mutex_lock(&s->lock);
while (nb_sectors > 0) { while (nb_sectors > 0) {
int64_t block_offset = seek_to_sector(bs, sector_num); int64_t block_offset = seek_to_sector(bs, sector_num);
if (block_offset < 0) { if (block_offset < 0) {
return block_offset; ret = block_offset;
} else if (block_offset > 0) { goto fail;
ret = bdrv_pread(bs->file->bs, block_offset, buf, 512); }
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, 512);
if (block_offset > 0) {
ret = bdrv_co_preadv(bs->file->bs, block_offset, 512,
&local_qiov, 0);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
} }
} else { } else {
memset(buf, 0, 512); qemu_iovec_memset(&local_qiov, 0, 0, 512);
} }
nb_sectors--; nb_sectors--;
sector_num++; sector_num++;
buf += 512; bytes_done += 512;
} }
return 0;
}
static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num, ret = 0;
uint8_t *buf, int nb_sectors) fail:
{
int ret;
BDRVBochsState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = bochs_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
qemu_iovec_destroy(&local_qiov);
return ret; return ret;
} }
@ -267,7 +282,7 @@ static BlockDriver bdrv_bochs = {
.instance_size = sizeof(BDRVBochsState), .instance_size = sizeof(BDRVBochsState),
.bdrv_probe = bochs_probe, .bdrv_probe = bochs_probe,
.bdrv_open = bochs_open, .bdrv_open = bochs_open,
.bdrv_read = bochs_co_read, .bdrv_co_preadv = bochs_co_preadv,
.bdrv_close = bochs_close, .bdrv_close = bochs_close,
}; };

View File

@ -66,6 +66,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
bs->read_only = 1; bs->read_only = 1;
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
/* read header */ /* read header */
ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4); ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4);
@ -229,33 +230,38 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
return 0; return 0;
} }
static int cloop_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) cloop_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVCloopState *s = bs->opaque; BDRVCloopState *s = bs->opaque;
int i; uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
int ret, i;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
qemu_co_mutex_lock(&s->lock);
for (i = 0; i < nb_sectors; i++) { for (i = 0; i < nb_sectors; i++) {
void *data;
uint32_t sector_offset_in_block = uint32_t sector_offset_in_block =
((sector_num + i) % s->sectors_per_block), ((sector_num + i) % s->sectors_per_block),
block_num = (sector_num + i) / s->sectors_per_block; block_num = (sector_num + i) / s->sectors_per_block;
if (cloop_read_block(bs, block_num) != 0) { if (cloop_read_block(bs, block_num) != 0) {
return -1; ret = -EIO;
goto fail;
} }
memcpy(buf + i * 512,
s->uncompressed_block + sector_offset_in_block * 512, 512);
}
return 0;
}
static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num, data = s->uncompressed_block + sector_offset_in_block * 512;
uint8_t *buf, int nb_sectors) qemu_iovec_from_buf(qiov, i * 512, data, 512);
{ }
int ret;
BDRVCloopState *s = bs->opaque; ret = 0;
qemu_co_mutex_lock(&s->lock); fail:
ret = cloop_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
} }
@ -273,7 +279,7 @@ static BlockDriver bdrv_cloop = {
.instance_size = sizeof(BDRVCloopState), .instance_size = sizeof(BDRVCloopState),
.bdrv_probe = cloop_probe, .bdrv_probe = cloop_probe,
.bdrv_open = cloop_open, .bdrv_open = cloop_open,
.bdrv_read = cloop_co_read, .bdrv_co_preadv = cloop_co_preadv,
.bdrv_close = cloop_close, .bdrv_close = cloop_close,
}; };

View File

@ -91,7 +91,7 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
struct BlockCryptoCreateData *data = opaque; struct BlockCryptoCreateData *data = opaque;
ssize_t ret; ssize_t ret;
ret = blk_pwrite(data->blk, offset, buf, buflen); ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header"); error_setg_errno(errp, -ret, "Could not write encryption header");
return ret; return ret;

View File

@ -36,10 +36,16 @@
// #define DEBUG_VERBOSE // #define DEBUG_VERBOSE
#ifdef DEBUG_CURL #ifdef DEBUG_CURL
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0) #define DEBUG_CURL_PRINT 1
#else #else
#define DPRINTF(fmt, ...) do { } while (0) #define DEBUG_CURL_PRINT 0
#endif #endif
#define DPRINTF(fmt, ...) \
do { \
if (DEBUG_CURL_PRINT) { \
fprintf(stderr, fmt, ## __VA_ARGS__); \
} \
} while (0)
#if LIBCURL_VERSION_NUM >= 0x071000 #if LIBCURL_VERSION_NUM >= 0x071000
/* The multi interface timer callback was introduced in 7.16.0 */ /* The multi interface timer callback was introduced in 7.16.0 */

View File

@ -440,6 +440,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
bs->read_only = 1; bs->read_only = 1;
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
s->n_chunks = 0; s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
/* used by dmg_read_mish_block to keep track of the current I/O position */ /* used by dmg_read_mish_block to keep track of the current I/O position */
@ -659,38 +661,42 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return 0; return 0;
} }
static int dmg_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVDMGState *s = bs->opaque; BDRVDMGState *s = bs->opaque;
int i; uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
int ret, i;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
qemu_co_mutex_lock(&s->lock);
for (i = 0; i < nb_sectors; i++) { for (i = 0; i < nb_sectors; i++) {
uint32_t sector_offset_in_chunk; uint32_t sector_offset_in_chunk;
void *data;
if (dmg_read_chunk(bs, sector_num + i) != 0) { if (dmg_read_chunk(bs, sector_num + i) != 0) {
return -1; ret = -EIO;
goto fail;
} }
/* Special case: current chunk is all zeroes. Do not perform a memcpy as /* Special case: current chunk is all zeroes. Do not perform a memcpy as
* s->uncompressed_chunk may be too small to cover the large all-zeroes * s->uncompressed_chunk may be too small to cover the large all-zeroes
* section. dmg_read_chunk is called to find s->current_chunk */ * section. dmg_read_chunk is called to find s->current_chunk */
if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */ if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */
memset(buf + i * 512, 0, 512); qemu_iovec_memset(qiov, i * 512, 0, 512);
continue; continue;
} }
sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk]; sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
memcpy(buf + i * 512, data = s->uncompressed_chunk + sector_offset_in_chunk * 512;
s->uncompressed_chunk + sector_offset_in_chunk * 512, 512); qemu_iovec_from_buf(qiov, i * 512, data, 512);
} }
return 0;
}
static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num, ret = 0;
uint8_t *buf, int nb_sectors) fail:
{
int ret;
BDRVDMGState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = dmg_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
} }
@ -715,7 +721,7 @@ static BlockDriver bdrv_dmg = {
.instance_size = sizeof(BDRVDMGState), .instance_size = sizeof(BDRVDMGState),
.bdrv_probe = dmg_probe, .bdrv_probe = dmg_probe,
.bdrv_open = dmg_open, .bdrv_open = dmg_open,
.bdrv_read = dmg_co_read, .bdrv_co_preadv = dmg_co_preadv,
.bdrv_close = dmg_close, .bdrv_close = dmg_close,
}; };

View File

@ -34,18 +34,6 @@
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque);
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque);
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num, int64_t sector_num,
QEMUIOVector *qiov, QEMUIOVector *qiov,
@ -62,48 +50,35 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
void bdrv_set_io_limits(BlockDriverState *bs, void bdrv_set_io_limits(BlockDriverState *bs,
ThrottleConfig *cfg) ThrottleConfig *cfg)
{ {
int i;
throttle_group_config(bs, cfg); throttle_group_config(bs, cfg);
}
for (i = 0; i < 2; i++) { void bdrv_no_throttling_begin(BlockDriverState *bs)
qemu_co_enter_next(&bs->throttled_reqs[i]); {
if (bs->io_limits_disabled++ == 0) {
throttle_group_restart_bs(bs);
} }
} }
/* this function drain all the throttled IOs */ void bdrv_no_throttling_end(BlockDriverState *bs)
static bool bdrv_start_throttled_reqs(BlockDriverState *bs)
{ {
bool drained = false; assert(bs->io_limits_disabled);
bool enabled = bs->io_limits_enabled; --bs->io_limits_disabled;
int i;
bs->io_limits_enabled = false;
for (i = 0; i < 2; i++) {
while (qemu_co_enter_next(&bs->throttled_reqs[i])) {
drained = true;
}
}
bs->io_limits_enabled = enabled;
return drained;
} }
void bdrv_io_limits_disable(BlockDriverState *bs) void bdrv_io_limits_disable(BlockDriverState *bs)
{ {
bs->io_limits_enabled = false; assert(bs->throttle_state);
bdrv_start_throttled_reqs(bs); bdrv_no_throttling_begin(bs);
throttle_group_unregister_bs(bs); throttle_group_unregister_bs(bs);
bdrv_no_throttling_end(bs);
} }
/* should be called before bdrv_set_io_limits if a limit is set */ /* should be called before bdrv_set_io_limits if a limit is set */
void bdrv_io_limits_enable(BlockDriverState *bs, const char *group) void bdrv_io_limits_enable(BlockDriverState *bs, const char *group)
{ {
assert(!bs->io_limits_enabled); assert(!bs->throttle_state);
throttle_group_register_bs(bs, group); throttle_group_register_bs(bs, group);
bs->io_limits_enabled = true;
} }
void bdrv_io_limits_update_group(BlockDriverState *bs, const char *group) void bdrv_io_limits_update_group(BlockDriverState *bs, const char *group)
@ -123,24 +98,6 @@ void bdrv_io_limits_update_group(BlockDriverState *bs, const char *group)
bdrv_io_limits_enable(bs, group); bdrv_io_limits_enable(bs, group);
} }
void bdrv_setup_io_funcs(BlockDriver *bdrv)
{
/* Block drivers without coroutine functions need emulation */
if (!bdrv->bdrv_co_readv) {
bdrv->bdrv_co_readv = bdrv_co_readv_em;
bdrv->bdrv_co_writev = bdrv_co_writev_em;
/* bdrv_co_readv_em()/brdv_co_writev_em() work in terms of aio, so if
* the block driver lacks aio we need to emulate that too.
*/
if (!bdrv->bdrv_aio_readv) {
/* add AIO emulation layer */
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
}
}
}
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
@ -260,18 +217,29 @@ typedef struct {
bool done; bool done;
} BdrvCoDrainData; } BdrvCoDrainData;
static void bdrv_drain_poll(BlockDriverState *bs)
{
bool busy = true;
while (busy) {
/* Keep iterating */
busy = bdrv_requests_pending(bs);
busy |= aio_poll(bdrv_get_aio_context(bs), busy);
}
}
static void bdrv_co_drain_bh_cb(void *opaque) static void bdrv_co_drain_bh_cb(void *opaque)
{ {
BdrvCoDrainData *data = opaque; BdrvCoDrainData *data = opaque;
Coroutine *co = data->co; Coroutine *co = data->co;
qemu_bh_delete(data->bh); qemu_bh_delete(data->bh);
bdrv_drain(data->bs); bdrv_drain_poll(data->bs);
data->done = true; data->done = true;
qemu_coroutine_enter(co, NULL); qemu_coroutine_enter(co, NULL);
} }
void coroutine_fn bdrv_co_drain(BlockDriverState *bs) static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
{ {
BdrvCoDrainData data; BdrvCoDrainData data;
@ -305,21 +273,28 @@ void coroutine_fn bdrv_co_drain(BlockDriverState *bs)
* not depend on events in other AioContexts. In that case, use * not depend on events in other AioContexts. In that case, use
* bdrv_drain_all() instead. * bdrv_drain_all() instead.
*/ */
void coroutine_fn bdrv_co_drain(BlockDriverState *bs)
{
bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs);
bdrv_co_yield_to_drain(bs);
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs);
}
void bdrv_drain(BlockDriverState *bs) void bdrv_drain(BlockDriverState *bs)
{ {
bool busy = true; bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs); bdrv_drain_recurse(bs);
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_drain(bs); bdrv_co_yield_to_drain(bs);
return; } else {
} bdrv_drain_poll(bs);
while (busy) {
/* Keep iterating */
bdrv_flush_io_queue(bs);
busy = bdrv_requests_pending(bs);
busy |= aio_poll(bdrv_get_aio_context(bs), busy);
} }
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs);
} }
/* /*
@ -342,6 +317,8 @@ void bdrv_drain_all(void)
if (bs->job) { if (bs->job) {
block_job_pause(bs->job); block_job_pause(bs->job);
} }
bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs); bdrv_drain_recurse(bs);
aio_context_release(aio_context); aio_context_release(aio_context);
@ -366,7 +343,6 @@ void bdrv_drain_all(void)
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
while ((bs = bdrv_next(bs))) { while ((bs = bdrv_next(bs))) {
if (aio_context == bdrv_get_aio_context(bs)) { if (aio_context == bdrv_get_aio_context(bs)) {
bdrv_flush_io_queue(bs);
if (bdrv_requests_pending(bs)) { if (bdrv_requests_pending(bs)) {
busy = true; busy = true;
aio_poll(aio_context, busy); aio_poll(aio_context, busy);
@ -383,6 +359,8 @@ void bdrv_drain_all(void)
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs);
if (bs->job) { if (bs->job) {
block_job_resume(bs->job); block_job_resume(bs->job);
} }
@ -581,13 +559,13 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
RwCo *rwco = opaque; RwCo *rwco = opaque;
if (!rwco->is_write) { if (!rwco->is_write) {
rwco->ret = bdrv_co_do_preadv(rwco->bs, rwco->offset, rwco->ret = bdrv_co_preadv(rwco->bs, rwco->offset,
rwco->qiov->size, rwco->qiov, rwco->qiov->size, rwco->qiov,
rwco->flags); rwco->flags);
} else { } else {
rwco->ret = bdrv_co_do_pwritev(rwco->bs, rwco->offset, rwco->ret = bdrv_co_pwritev(rwco->bs, rwco->offset,
rwco->qiov->size, rwco->qiov, rwco->qiov->size, rwco->qiov,
rwco->flags); rwco->flags);
} }
} }
@ -608,17 +586,6 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset,
.flags = flags, .flags = flags,
}; };
/**
* In sync call context, when the vcpu is blocked, this throttling timer
* will not fire; so the I/O throttling function has to be disabled here
* if it has been enabled.
*/
if (bs->io_limits_enabled) {
fprintf(stderr, "Disabling I/O throttling on '%s' due "
"to synchronous I/O.\n", bdrv_get_device_name(bs));
bdrv_io_limits_disable(bs);
}
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */ /* Fast-path if already in coroutine context */
bdrv_rw_co_entry(&rwco); bdrv_rw_co_entry(&rwco);
@ -685,7 +652,8 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
* Completely zero out a block device with the help of bdrv_write_zeroes. * Completely zero out a block device with the help of bdrv_write_zeroes.
* The operation is sped up by checking the block status and only writing * The operation is sped up by checking the block status and only writing
* zeroes to the device if they currently do not return zeroes. Optional * zeroes to the device if they currently do not return zeroes. Optional
* flags are passed through to bdrv_write_zeroes (e.g. BDRV_REQ_MAY_UNMAP). * flags are passed through to bdrv_write_zeroes (e.g. BDRV_REQ_MAY_UNMAP,
* BDRV_REQ_FUA).
* *
* Returns < 0 on error, 0 on success. For error codes see bdrv_write(). * Returns < 0 on error, 0 on success. For error codes see bdrv_write().
*/ */
@ -800,6 +768,109 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
return 0; return 0;
} }
typedef struct CoroutineIOCompletion {
Coroutine *coroutine;
int ret;
} CoroutineIOCompletion;
static void bdrv_co_io_em_complete(void *opaque, int ret)
{
CoroutineIOCompletion *co = opaque;
co->ret = ret;
qemu_coroutine_enter(co->coroutine, NULL);
}
static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
BlockDriver *drv = bs->drv;
int64_t sector_num;
unsigned int nb_sectors;
if (drv->bdrv_co_preadv) {
return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags);
}
sector_num = offset >> BDRV_SECTOR_BITS;
nb_sectors = bytes >> BDRV_SECTOR_BITS;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
if (drv->bdrv_co_readv) {
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
} else {
BlockAIOCB *acb;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
acb = bs->drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
bdrv_co_io_em_complete, &co);
if (acb == NULL) {
return -EIO;
} else {
qemu_coroutine_yield();
return co.ret;
}
}
}
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
BlockDriver *drv = bs->drv;
int64_t sector_num;
unsigned int nb_sectors;
int ret;
if (drv->bdrv_co_pwritev) {
ret = drv->bdrv_co_pwritev(bs, offset, bytes, qiov, flags);
goto emulate_flags;
}
sector_num = offset >> BDRV_SECTOR_BITS;
nb_sectors = bytes >> BDRV_SECTOR_BITS;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
if (drv->bdrv_co_writev_flags) {
ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
flags & bs->supported_write_flags);
flags &= ~bs->supported_write_flags;
} else if (drv->bdrv_co_writev) {
assert(!bs->supported_write_flags);
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
} else {
BlockAIOCB *acb;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
acb = bs->drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
bdrv_co_io_em_complete, &co);
if (acb == NULL) {
ret = -EIO;
} else {
qemu_coroutine_yield();
ret = co.ret;
}
}
emulate_flags:
if (ret == 0 && (flags & BDRV_REQ_FUA)) {
ret = bdrv_co_flush(bs);
}
return ret;
}
static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{ {
@ -836,8 +907,9 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
qemu_iovec_init_external(&bounce_qiov, &iov, 1); qemu_iovec_init_external(&bounce_qiov, &iov, 1);
ret = drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors, ret = bdrv_driver_preadv(bs, cluster_sector_num * BDRV_SECTOR_SIZE,
&bounce_qiov); cluster_nb_sectors * BDRV_SECTOR_SIZE,
&bounce_qiov, 0);
if (ret < 0) { if (ret < 0) {
goto err; goto err;
} }
@ -850,8 +922,9 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
/* This does not change the data on the disk, it is not necessary /* This does not change the data on the disk, it is not necessary
* to flush even in cache=writethrough mode. * to flush even in cache=writethrough mode.
*/ */
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors, ret = bdrv_driver_pwritev(bs, cluster_sector_num * BDRV_SECTOR_SIZE,
&bounce_qiov); cluster_nb_sectors * BDRV_SECTOR_SIZE,
&bounce_qiov, 0);
} }
if (ret < 0) { if (ret < 0) {
@ -880,7 +953,6 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes, BdrvTrackedRequest *req, int64_t offset, unsigned int bytes,
int64_t align, QEMUIOVector *qiov, int flags) int64_t align, QEMUIOVector *qiov, int flags)
{ {
BlockDriver *drv = bs->drv;
int ret; int ret;
int64_t sector_num = offset >> BDRV_SECTOR_BITS; int64_t sector_num = offset >> BDRV_SECTOR_BITS;
@ -921,7 +993,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
/* Forward the request to the BlockDriver */ /* Forward the request to the BlockDriver */
if (!bs->zero_beyond_eof) { if (!bs->zero_beyond_eof) {
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); ret = bdrv_driver_preadv(bs, offset, bytes, qiov, 0);
} else { } else {
/* Read zeros after EOF */ /* Read zeros after EOF */
int64_t total_sectors, max_nb_sectors; int64_t total_sectors, max_nb_sectors;
@ -935,7 +1007,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num), max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
align >> BDRV_SECTOR_BITS); align >> BDRV_SECTOR_BITS);
if (nb_sectors < max_nb_sectors) { if (nb_sectors < max_nb_sectors) {
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov); ret = bdrv_driver_preadv(bs, offset, bytes, qiov, 0);
} else if (max_nb_sectors > 0) { } else if (max_nb_sectors > 0) {
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
@ -943,8 +1015,9 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
qemu_iovec_concat(&local_qiov, qiov, 0, qemu_iovec_concat(&local_qiov, qiov, 0,
max_nb_sectors * BDRV_SECTOR_SIZE); max_nb_sectors * BDRV_SECTOR_SIZE);
ret = drv->bdrv_co_readv(bs, sector_num, max_nb_sectors, ret = bdrv_driver_preadv(bs, offset,
&local_qiov); max_nb_sectors * BDRV_SECTOR_SIZE,
&local_qiov, 0);
qemu_iovec_destroy(&local_qiov); qemu_iovec_destroy(&local_qiov);
} else { } else {
@ -967,7 +1040,7 @@ out:
/* /*
* Handle a read request in coroutine context * Handle a read request in coroutine context
*/ */
int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, int coroutine_fn bdrv_co_preadv(BlockDriverState *bs,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
@ -997,7 +1070,7 @@ int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
} }
/* throttling disk I/O */ /* throttling disk I/O */
if (bs->io_limits_enabled) { if (bs->throttle_state) {
throttle_group_co_io_limits_intercept(bs, bytes, false); throttle_group_co_io_limits_intercept(bs, bytes, false);
} }
@ -1049,8 +1122,8 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
return -EINVAL; return -EINVAL;
} }
return bdrv_co_do_preadv(bs, sector_num << BDRV_SECTOR_BITS, return bdrv_co_preadv(bs, sector_num << BDRV_SECTOR_BITS,
nb_sectors << BDRV_SECTOR_BITS, qiov, flags); nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
} }
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
@ -1088,6 +1161,7 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
QEMUIOVector qiov; QEMUIOVector qiov;
struct iovec iov = {0}; struct iovec iov = {0};
int ret = 0; int ret = 0;
bool need_flush = false;
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_write_zeroes, int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_write_zeroes,
BDRV_REQUEST_MAX_SECTORS); BDRV_REQUEST_MAX_SECTORS);
@ -1120,13 +1194,29 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
ret = -ENOTSUP; ret = -ENOTSUP;
/* First try the efficient write zeroes operation */ /* First try the efficient write zeroes operation */
if (drv->bdrv_co_write_zeroes) { if (drv->bdrv_co_write_zeroes) {
ret = drv->bdrv_co_write_zeroes(bs, sector_num, num, flags); ret = drv->bdrv_co_write_zeroes(bs, sector_num, num,
flags & bs->supported_zero_flags);
if (ret != -ENOTSUP && (flags & BDRV_REQ_FUA) &&
!(bs->supported_zero_flags & BDRV_REQ_FUA)) {
need_flush = true;
}
} else {
assert(!bs->supported_zero_flags);
} }
if (ret == -ENOTSUP) { if (ret == -ENOTSUP) {
/* Fall back to bounce buffer if write zeroes is unsupported */ /* Fall back to bounce buffer if write zeroes is unsupported */
int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length, int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length,
MAX_WRITE_ZEROES_BOUNCE_BUFFER); MAX_WRITE_ZEROES_BOUNCE_BUFFER);
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
if ((flags & BDRV_REQ_FUA) &&
!(bs->supported_write_flags & BDRV_REQ_FUA)) {
/* No need for bdrv_driver_pwrite() to do a fallback
* flush on each chunk; use just one at the end */
write_flags &= ~BDRV_REQ_FUA;
need_flush = true;
}
num = MIN(num, max_xfer_len); num = MIN(num, max_xfer_len);
iov.iov_len = num * BDRV_SECTOR_SIZE; iov.iov_len = num * BDRV_SECTOR_SIZE;
if (iov.iov_base == NULL) { if (iov.iov_base == NULL) {
@ -1139,7 +1229,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
} }
qemu_iovec_init_external(&qiov, &iov, 1); qemu_iovec_init_external(&qiov, &iov, 1);
ret = drv->bdrv_co_writev(bs, sector_num, num, &qiov); ret = bdrv_driver_pwritev(bs, sector_num * BDRV_SECTOR_SIZE,
num * BDRV_SECTOR_SIZE, &qiov,
write_flags);
/* Keep bounce buffer around if it is big enough for all /* Keep bounce buffer around if it is big enough for all
* all future requests. * all future requests.
@ -1155,6 +1247,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
} }
fail: fail:
if (ret == 0 && need_flush) {
ret = bdrv_co_flush(bs);
}
qemu_vfree(iov.iov_base); qemu_vfree(iov.iov_base);
return ret; return ret;
} }
@ -1199,23 +1294,12 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
} else if (flags & BDRV_REQ_ZERO_WRITE) { } else if (flags & BDRV_REQ_ZERO_WRITE) {
bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO); bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags); ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags);
} else if (drv->bdrv_co_writev_flags) {
bdrv_debug_event(bs, BLKDBG_PWRITEV);
ret = drv->bdrv_co_writev_flags(bs, sector_num, nb_sectors, qiov,
flags);
} else { } else {
assert(drv->supported_write_flags == 0);
bdrv_debug_event(bs, BLKDBG_PWRITEV); bdrv_debug_event(bs, BLKDBG_PWRITEV);
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov); ret = bdrv_driver_pwritev(bs, offset, bytes, qiov, flags);
} }
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE); bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
if (ret == 0 && (flags & BDRV_REQ_FUA) &&
!(drv->supported_write_flags & BDRV_REQ_FUA))
{
ret = bdrv_co_flush(bs);
}
bdrv_set_dirty(bs, sector_num, nb_sectors); bdrv_set_dirty(bs, sector_num, nb_sectors);
if (bs->wr_highest_offset < offset + bytes) { if (bs->wr_highest_offset < offset + bytes) {
@ -1320,7 +1404,7 @@ fail:
/* /*
* Handle a write request in coroutine context * Handle a write request in coroutine context
*/ */
int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
@ -1347,7 +1431,7 @@ int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
} }
/* throttling disk I/O */ /* throttling disk I/O */
if (bs->io_limits_enabled) { if (bs->throttle_state) {
throttle_group_co_io_limits_intercept(bs, bytes, true); throttle_group_co_io_limits_intercept(bs, bytes, true);
} }
@ -1455,8 +1539,8 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
return -EINVAL; return -EINVAL;
} }
return bdrv_co_do_pwritev(bs, sector_num << BDRV_SECTOR_BITS, return bdrv_co_pwritev(bs, sector_num << BDRV_SECTOR_BITS,
nb_sectors << BDRV_SECTOR_BITS, qiov, flags); nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
} }
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
@ -2064,80 +2148,6 @@ void bdrv_aio_cancel_async(BlockAIOCB *acb)
/**************************************************************/ /**************************************************************/
/* async block device emulation */ /* async block device emulation */
typedef struct BlockAIOCBSync {
BlockAIOCB common;
QEMUBH *bh;
int ret;
/* vector translation state */
QEMUIOVector *qiov;
uint8_t *bounce;
int is_write;
} BlockAIOCBSync;
static const AIOCBInfo bdrv_em_aiocb_info = {
.aiocb_size = sizeof(BlockAIOCBSync),
};
static void bdrv_aio_bh_cb(void *opaque)
{
BlockAIOCBSync *acb = opaque;
if (!acb->is_write && acb->ret >= 0) {
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
}
qemu_vfree(acb->bounce);
acb->common.cb(acb->common.opaque, acb->ret);
qemu_bh_delete(acb->bh);
acb->bh = NULL;
qemu_aio_unref(acb);
}
static BlockAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque,
int is_write)
{
BlockAIOCBSync *acb;
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
acb->is_write = is_write;
acb->qiov = qiov;
acb->bounce = qemu_try_blockalign(bs, qiov->size);
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_aio_bh_cb, acb);
if (acb->bounce == NULL) {
acb->ret = -ENOMEM;
} else if (is_write) {
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
acb->ret = bs->drv->bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
} else {
acb->ret = bs->drv->bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
}
qemu_bh_schedule(acb->bh);
return &acb->common;
}
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
typedef struct BlockAIOCBCoroutine { typedef struct BlockAIOCBCoroutine {
BlockAIOCB common; BlockAIOCB common;
BlockRequest req; BlockRequest req;
@ -2314,59 +2324,6 @@ void qemu_aio_unref(void *p)
/**************************************************************/ /**************************************************************/
/* Coroutine block device emulation */ /* Coroutine block device emulation */
typedef struct CoroutineIOCompletion {
Coroutine *coroutine;
int ret;
} CoroutineIOCompletion;
static void bdrv_co_io_em_complete(void *opaque, int ret)
{
CoroutineIOCompletion *co = opaque;
co->ret = ret;
qemu_coroutine_enter(co->coroutine, NULL);
}
static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *iov,
bool is_write)
{
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
BlockAIOCB *acb;
if (is_write) {
acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
} else {
acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
}
trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
if (!acb) {
return -EIO;
}
qemu_coroutine_yield();
return co.ret;
}
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{
return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, false);
}
static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{
return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
}
static void coroutine_fn bdrv_flush_co_entry(void *opaque) static void coroutine_fn bdrv_flush_co_entry(void *opaque)
{ {
RwCo *rwco = opaque; RwCo *rwco = opaque;
@ -2763,33 +2720,68 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
void bdrv_io_plug(BlockDriverState *bs) void bdrv_io_plug(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs); QLIST_FOREACH(child, &bs->children, next) {
} else if (bs->file) { bdrv_io_plug(child->bs);
bdrv_io_plug(bs->file->bs); }
if (bs->io_plugged++ == 0 && bs->io_plug_disabled == 0) {
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs);
}
} }
} }
void bdrv_io_unplug(BlockDriverState *bs) void bdrv_io_unplug(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs); assert(bs->io_plugged);
} else if (bs->file) { if (--bs->io_plugged == 0 && bs->io_plug_disabled == 0) {
bdrv_io_unplug(bs->file->bs); BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs);
}
}
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplug(child->bs);
} }
} }
void bdrv_flush_io_queue(BlockDriverState *bs) void bdrv_io_unplugged_begin(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_flush_io_queue) {
drv->bdrv_flush_io_queue(bs); if (bs->io_plug_disabled++ == 0 && bs->io_plugged > 0) {
} else if (bs->file) { BlockDriver *drv = bs->drv;
bdrv_flush_io_queue(bs->file->bs); if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs);
}
}
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplugged_begin(child->bs);
}
}
void bdrv_io_unplugged_end(BlockDriverState *bs)
{
BdrvChild *child;
assert(bs->io_plug_disabled);
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplugged_end(child->bs);
}
if (--bs->io_plug_disabled == 0 && bs->io_plugged > 0) {
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs);
}
} }
bdrv_start_throttled_reqs(bs);
} }
void bdrv_drained_begin(BlockDriverState *bs) void bdrv_drained_begin(BlockDriverState *bs)

View File

@ -456,8 +456,11 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
struct IscsiTask iTask; struct IscsiTask iTask;
uint64_t lba; uint64_t lba;
uint32_t num_sectors; uint32_t num_sectors;
bool fua; bool fua = flags & BDRV_REQ_FUA;
if (fua) {
assert(iscsilun->dpofua);
}
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
return -EINVAL; return -EINVAL;
} }
@ -472,7 +475,6 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
num_sectors = sector_qemu2lun(nb_sectors, iscsilun); num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
fua = iscsilun->dpofua && (flags & BDRV_REQ_FUA);
if (iscsilun->use_16_for_rw) { if (iscsilun->use_16_for_rw) {
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
NULL, num_sectors * iscsilun->block_size, NULL, num_sectors * iscsilun->block_size,
@ -513,13 +515,6 @@ retry:
return 0; return 0;
} }
static int coroutine_fn
iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
QEMUIOVector *iov)
{
return iscsi_co_writev_flags(bs, sector_num, nb_sectors, iov, 0);
}
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun, static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
int64_t sector_num, int nb_sectors) int64_t sector_num, int nb_sectors)
@ -1555,6 +1550,10 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
task = NULL; task = NULL;
iscsi_modesense_sync(iscsilun); iscsi_modesense_sync(iscsilun);
if (iscsilun->dpofua) {
bs->supported_write_flags = BDRV_REQ_FUA;
}
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
/* Check the write protect flag of the LUN if we want to write */ /* Check the write protect flag of the LUN if we want to write */
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
@ -1847,9 +1846,7 @@ static BlockDriver bdrv_iscsi = {
.bdrv_co_discard = iscsi_co_discard, .bdrv_co_discard = iscsi_co_discard,
.bdrv_co_write_zeroes = iscsi_co_write_zeroes, .bdrv_co_write_zeroes = iscsi_co_write_zeroes,
.bdrv_co_readv = iscsi_co_readv, .bdrv_co_readv = iscsi_co_readv,
.bdrv_co_writev = iscsi_co_writev,
.bdrv_co_writev_flags = iscsi_co_writev_flags, .bdrv_co_writev_flags = iscsi_co_writev_flags,
.supported_write_flags = BDRV_REQ_FUA,
.bdrv_co_flush_to_disk = iscsi_co_flush, .bdrv_co_flush_to_disk = iscsi_co_flush,
#ifdef __linux__ #ifdef __linux__

View File

@ -30,7 +30,7 @@
struct qemu_laiocb { struct qemu_laiocb {
BlockAIOCB common; BlockAIOCB common;
struct qemu_laio_state *ctx; LinuxAioState *ctx;
struct iocb iocb; struct iocb iocb;
ssize_t ret; ssize_t ret;
size_t nbytes; size_t nbytes;
@ -46,7 +46,7 @@ typedef struct {
QSIMPLEQ_HEAD(, qemu_laiocb) pending; QSIMPLEQ_HEAD(, qemu_laiocb) pending;
} LaioQueue; } LaioQueue;
struct qemu_laio_state { struct LinuxAioState {
io_context_t ctx; io_context_t ctx;
EventNotifier e; EventNotifier e;
@ -60,7 +60,7 @@ struct qemu_laio_state {
int event_max; int event_max;
}; };
static void ioq_submit(struct qemu_laio_state *s); static void ioq_submit(LinuxAioState *s);
static inline ssize_t io_event_ret(struct io_event *ev) static inline ssize_t io_event_ret(struct io_event *ev)
{ {
@ -70,8 +70,7 @@ static inline ssize_t io_event_ret(struct io_event *ev)
/* /*
* Completes an AIO request (calls the callback and frees the ACB). * Completes an AIO request (calls the callback and frees the ACB).
*/ */
static void qemu_laio_process_completion(struct qemu_laio_state *s, static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
struct qemu_laiocb *laiocb)
{ {
int ret; int ret;
@ -99,7 +98,7 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
* *
* The function is somewhat tricky because it supports nested event loops, for * The function is somewhat tricky because it supports nested event loops, for
* example when a request callback invokes aio_poll(). In order to do this, * example when a request callback invokes aio_poll(). In order to do this,
* the completion events array and index are kept in qemu_laio_state. The BH * the completion events array and index are kept in LinuxAioState. The BH
* reschedules itself as long as there are completions pending so it will * reschedules itself as long as there are completions pending so it will
* either be called again in a nested event loop or will be called after all * either be called again in a nested event loop or will be called after all
* events have been completed. When there are no events left to complete, the * events have been completed. When there are no events left to complete, the
@ -107,7 +106,7 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
*/ */
static void qemu_laio_completion_bh(void *opaque) static void qemu_laio_completion_bh(void *opaque)
{ {
struct qemu_laio_state *s = opaque; LinuxAioState *s = opaque;
/* Fetch more completion events when empty */ /* Fetch more completion events when empty */
if (s->event_idx == s->event_max) { if (s->event_idx == s->event_max) {
@ -136,7 +135,7 @@ static void qemu_laio_completion_bh(void *opaque)
laiocb->ret = io_event_ret(&s->events[s->event_idx]); laiocb->ret = io_event_ret(&s->events[s->event_idx]);
s->event_idx++; s->event_idx++;
qemu_laio_process_completion(s, laiocb); qemu_laio_process_completion(laiocb);
} }
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
@ -146,7 +145,7 @@ static void qemu_laio_completion_bh(void *opaque)
static void qemu_laio_completion_cb(EventNotifier *e) static void qemu_laio_completion_cb(EventNotifier *e)
{ {
struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e); LinuxAioState *s = container_of(e, LinuxAioState, e);
if (event_notifier_test_and_clear(&s->e)) { if (event_notifier_test_and_clear(&s->e)) {
qemu_bh_schedule(s->completion_bh); qemu_bh_schedule(s->completion_bh);
@ -185,7 +184,7 @@ static void ioq_init(LaioQueue *io_q)
io_q->blocked = false; io_q->blocked = false;
} }
static void ioq_submit(struct qemu_laio_state *s) static void ioq_submit(LinuxAioState *s)
{ {
int ret, len; int ret, len;
struct qemu_laiocb *aiocb; struct qemu_laiocb *aiocb;
@ -216,33 +215,25 @@ static void ioq_submit(struct qemu_laio_state *s)
s->io_q.blocked = (s->io_q.n > 0); s->io_q.blocked = (s->io_q.n > 0);
} }
void laio_io_plug(BlockDriverState *bs, void *aio_ctx) void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
{ {
struct qemu_laio_state *s = aio_ctx; assert(!s->io_q.plugged);
s->io_q.plugged = 1;
s->io_q.plugged++;
} }
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug) void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s)
{ {
struct qemu_laio_state *s = aio_ctx; assert(s->io_q.plugged);
s->io_q.plugged = 0;
assert(s->io_q.plugged > 0 || !unplug);
if (unplug && --s->io_q.plugged > 0) {
return;
}
if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
ioq_submit(s); ioq_submit(s);
} }
} }
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque, int type) BlockCompletionFunc *cb, void *opaque, int type)
{ {
struct qemu_laio_state *s = aio_ctx;
struct qemu_laiocb *laiocb; struct qemu_laiocb *laiocb;
struct iocb *iocbs; struct iocb *iocbs;
off_t offset = sector_num * 512; off_t offset = sector_num * 512;
@ -284,26 +275,22 @@ out_free_aiocb:
return NULL; return NULL;
} }
void laio_detach_aio_context(void *s_, AioContext *old_context) void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
{ {
struct qemu_laio_state *s = s_;
aio_set_event_notifier(old_context, &s->e, false, NULL); aio_set_event_notifier(old_context, &s->e, false, NULL);
qemu_bh_delete(s->completion_bh); qemu_bh_delete(s->completion_bh);
} }
void laio_attach_aio_context(void *s_, AioContext *new_context) void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
{ {
struct qemu_laio_state *s = s_;
s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s); s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s);
aio_set_event_notifier(new_context, &s->e, false, aio_set_event_notifier(new_context, &s->e, false,
qemu_laio_completion_cb); qemu_laio_completion_cb);
} }
void *laio_init(void) LinuxAioState *laio_init(void)
{ {
struct qemu_laio_state *s; LinuxAioState *s;
s = g_malloc0(sizeof(*s)); s = g_malloc0(sizeof(*s));
if (event_notifier_init(&s->e, false) < 0) { if (event_notifier_init(&s->e, false) < 0) {
@ -325,10 +312,8 @@ out_free_state:
return NULL; return NULL;
} }
void laio_cleanup(void *s_) void laio_cleanup(LinuxAioState *s)
{ {
struct qemu_laio_state *s = s_;
event_notifier_cleanup(&s->e); event_notifier_cleanup(&s->e);
if (io_destroy(s->ctx) != 0) { if (io_destroy(s->ctx) != 0) {

View File

@ -243,15 +243,15 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num, static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov, int nb_sectors, QEMUIOVector *qiov,
int offset, int *flags) int offset, int flags)
{ {
NbdClientSession *client = nbd_get_client_session(bs); NbdClientSession *client = nbd_get_client_session(bs);
struct nbd_request request = { .type = NBD_CMD_WRITE }; struct nbd_request request = { .type = NBD_CMD_WRITE };
struct nbd_reply reply; struct nbd_reply reply;
ssize_t ret; ssize_t ret;
if ((*flags & BDRV_REQ_FUA) && (client->nbdflags & NBD_FLAG_SEND_FUA)) { if (flags & BDRV_REQ_FUA) {
*flags &= ~BDRV_REQ_FUA; assert(client->nbdflags & NBD_FLAG_SEND_FUA);
request.type |= NBD_CMD_FLAG_FUA; request.type |= NBD_CMD_FLAG_FUA;
} }
@ -291,7 +291,7 @@ int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
} }
int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num, int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov, int *flags) int nb_sectors, QEMUIOVector *qiov, int flags)
{ {
int offset = 0; int offset = 0;
int ret; int ret;
@ -414,6 +414,9 @@ int nbd_client_init(BlockDriverState *bs,
logout("Failed to negotiate with the NBD server\n"); logout("Failed to negotiate with the NBD server\n");
return ret; return ret;
} }
if (client->nbdflags & NBD_FLAG_SEND_FUA) {
bs->supported_write_flags = BDRV_REQ_FUA;
}
qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->send_mutex);
qemu_co_mutex_init(&client->free_sema); qemu_co_mutex_init(&client->free_sema);

View File

@ -48,7 +48,7 @@ int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors); int nb_sectors);
int nbd_client_co_flush(BlockDriverState *bs); int nbd_client_co_flush(BlockDriverState *bs);
int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num, int nbd_client_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov, int *flags); int nb_sectors, QEMUIOVector *qiov, int flags);
int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num, int nbd_client_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov); int nb_sectors, QEMUIOVector *qiov);

View File

@ -355,31 +355,6 @@ static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
return nbd_client_co_readv(bs, sector_num, nb_sectors, qiov); return nbd_client_co_readv(bs, sector_num, nb_sectors, qiov);
} }
static int nbd_co_writev_flags(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov, int flags)
{
int ret;
ret = nbd_client_co_writev(bs, sector_num, nb_sectors, qiov, &flags);
if (ret < 0) {
return ret;
}
/* The flag wasn't sent to the server, so we need to emulate it with an
* explicit flush */
if (flags & BDRV_REQ_FUA) {
ret = nbd_client_co_flush(bs);
}
return ret;
}
static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
return nbd_co_writev_flags(bs, sector_num, nb_sectors, qiov, 0);
}
static int nbd_co_flush(BlockDriverState *bs) static int nbd_co_flush(BlockDriverState *bs)
{ {
return nbd_client_co_flush(bs); return nbd_client_co_flush(bs);
@ -476,9 +451,7 @@ static BlockDriver bdrv_nbd = {
.bdrv_parse_filename = nbd_parse_filename, .bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open, .bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv, .bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev, .bdrv_co_writev_flags = nbd_client_co_writev,
.bdrv_co_writev_flags = nbd_co_writev_flags,
.supported_write_flags = BDRV_REQ_FUA,
.bdrv_close = nbd_close, .bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard, .bdrv_co_discard = nbd_co_discard,
@ -496,9 +469,7 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_parse_filename = nbd_parse_filename, .bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open, .bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv, .bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev, .bdrv_co_writev_flags = nbd_client_co_writev,
.bdrv_co_writev_flags = nbd_co_writev_flags,
.supported_write_flags = BDRV_REQ_FUA,
.bdrv_close = nbd_close, .bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard, .bdrv_co_discard = nbd_co_discard,
@ -516,9 +487,7 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_parse_filename = nbd_parse_filename, .bdrv_parse_filename = nbd_parse_filename,
.bdrv_file_open = nbd_open, .bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv, .bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev, .bdrv_co_writev_flags = nbd_client_co_writev,
.bdrv_co_writev_flags = nbd_co_writev_flags,
.supported_write_flags = BDRV_REQ_FUA,
.bdrv_close = nbd_close, .bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard, .bdrv_co_discard = nbd_co_discard,

View File

@ -512,11 +512,12 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
memcpy(tmp, &header, sizeof(header)); memcpy(tmp, &header, sizeof(header));
ret = blk_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE); ret = blk_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
ret = blk_write_zeroes(file, 1, bat_sectors - 1, 0); ret = blk_write_zeroes(file, BDRV_SECTOR_SIZE,
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }

View File

@ -853,14 +853,14 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
} }
/* write all the data */ /* write all the data */
ret = blk_pwrite(qcow_blk, 0, &header, sizeof(header)); ret = blk_pwrite(qcow_blk, 0, &header, sizeof(header), 0);
if (ret != sizeof(header)) { if (ret != sizeof(header)) {
goto exit; goto exit;
} }
if (backing_file) { if (backing_file) {
ret = blk_pwrite(qcow_blk, sizeof(header), ret = blk_pwrite(qcow_blk, sizeof(header),
backing_file, backing_filename_len); backing_file, backing_filename_len, 0);
if (ret != backing_filename_len) { if (ret != backing_filename_len) {
goto exit; goto exit;
} }
@ -869,8 +869,8 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
tmp = g_malloc0(BDRV_SECTOR_SIZE); tmp = g_malloc0(BDRV_SECTOR_SIZE);
for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/ for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
BDRV_SECTOR_SIZE); i++) { BDRV_SECTOR_SIZE); i++) {
ret = blk_pwrite(qcow_blk, header_size + ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE); tmp, BDRV_SECTOR_SIZE, 0);
if (ret != BDRV_SECTOR_SIZE) { if (ret != BDRV_SECTOR_SIZE) {
g_free(tmp); g_free(tmp);
goto exit; goto exit;

View File

@ -1757,13 +1757,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
qcow2_close(bs); qcow2_close(bs);
bdrv_invalidate_cache(bs->file->bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
bs->drv = NULL;
return;
}
memset(s, 0, sizeof(BDRVQcow2State)); memset(s, 0, sizeof(BDRVQcow2State));
options = qdict_clone_shallow(bs->options); options = qdict_clone_shallow(bs->options);
@ -2207,7 +2200,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
} }
ret = blk_pwrite(blk, 0, header, cluster_size); ret = blk_pwrite(blk, 0, header, cluster_size, 0);
g_free(header); g_free(header);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write qcow2 header"); error_setg_errno(errp, -ret, "Could not write qcow2 header");
@ -2217,7 +2210,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
/* Write a refcount table with one refcount block */ /* Write a refcount table with one refcount block */
refcount_table = g_malloc0(2 * cluster_size); refcount_table = g_malloc0(2 * cluster_size);
refcount_table[0] = cpu_to_be64(2 * cluster_size); refcount_table[0] = cpu_to_be64(2 * cluster_size);
ret = blk_pwrite(blk, cluster_size, refcount_table, 2 * cluster_size); ret = blk_pwrite(blk, cluster_size, refcount_table, 2 * cluster_size, 0);
g_free(refcount_table); g_free(refcount_table);
if (ret < 0) { if (ret < 0) {
@ -2411,21 +2404,74 @@ finish:
return ret; return ret;
} }
static bool is_zero_cluster(BlockDriverState *bs, int64_t start)
{
BDRVQcow2State *s = bs->opaque;
int nr;
BlockDriverState *file;
int64_t res = bdrv_get_block_status_above(bs, NULL, start,
s->cluster_sectors, &nr, &file);
return res >= 0 && ((res & BDRV_BLOCK_ZERO) || !(res & BDRV_BLOCK_DATA));
}
static bool is_zero_cluster_top_locked(BlockDriverState *bs, int64_t start)
{
BDRVQcow2State *s = bs->opaque;
int nr = s->cluster_sectors;
uint64_t off;
int ret;
ret = qcow2_get_cluster_offset(bs, start << BDRV_SECTOR_BITS, &nr, &off);
return ret == QCOW2_CLUSTER_UNALLOCATED || ret == QCOW2_CLUSTER_ZERO;
}
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs, static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
{ {
int ret; int ret;
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
/* Emulate misaligned zero writes */ int head = sector_num % s->cluster_sectors;
if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) { int tail = (sector_num + nb_sectors) % s->cluster_sectors;
return -ENOTSUP;
if (head != 0 || tail != 0) {
int64_t cl_end = -1;
sector_num -= head;
nb_sectors += head;
if (tail != 0) {
nb_sectors += s->cluster_sectors - tail;
}
if (!is_zero_cluster(bs, sector_num)) {
return -ENOTSUP;
}
if (nb_sectors > s->cluster_sectors) {
/* Technically the request can cover 2 clusters, f.e. 4k write
at s->cluster_sectors - 2k offset. One of these cluster can
be zeroed, one unallocated */
cl_end = sector_num + nb_sectors - s->cluster_sectors;
if (!is_zero_cluster(bs, cl_end)) {
return -ENOTSUP;
}
}
qemu_co_mutex_lock(&s->lock);
/* We can have new write after previous check */
if (!is_zero_cluster_top_locked(bs, sector_num) ||
(cl_end > 0 && !is_zero_cluster_top_locked(bs, cl_end))) {
qemu_co_mutex_unlock(&s->lock);
return -ENOTSUP;
}
} else {
qemu_co_mutex_lock(&s->lock);
} }
/* Whatever is left can use real zero clusters */ /* Whatever is left can use real zero clusters */
qemu_co_mutex_lock(&s->lock); ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS, nb_sectors);
ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS,
nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;

View File

@ -601,18 +601,18 @@ static int qed_create(const char *filename, uint32_t cluster_size,
} }
qed_header_cpu_to_le(&header, &le_header); qed_header_cpu_to_le(&header, &le_header);
ret = blk_pwrite(blk, 0, &le_header, sizeof(le_header)); ret = blk_pwrite(blk, 0, &le_header, sizeof(le_header), 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
ret = blk_pwrite(blk, sizeof(le_header), backing_file, ret = blk_pwrite(blk, sizeof(le_header), backing_file,
header.backing_filename_size); header.backing_filename_size, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
l1_table = g_malloc0(l1_size); l1_table = g_malloc0(l1_size);
ret = blk_pwrite(blk, header.l1_table_offset, l1_table, l1_size); ret = blk_pwrite(blk, header.l1_table_offset, l1_table, l1_size, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@ -1594,12 +1594,6 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
bdrv_qed_close(bs); bdrv_qed_close(bs);
bdrv_invalidate_cache(bs->file->bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memset(s, 0, sizeof(BDRVQEDState)); memset(s, 0, sizeof(BDRVQEDState));
ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err); ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
if (local_err) { if (local_err) {

View File

@ -14,6 +14,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/qmp/qbool.h" #include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
@ -67,6 +68,9 @@ typedef struct QuorumVotes {
typedef struct BDRVQuorumState { typedef struct BDRVQuorumState {
BdrvChild **children; /* children BlockDriverStates */ BdrvChild **children; /* children BlockDriverStates */
int num_children; /* children count */ int num_children; /* children count */
unsigned next_child_index; /* the index of the next child that should
* be added
*/
int threshold; /* if less than threshold children reads gave the int threshold; /* if less than threshold children reads gave the
* same result a quorum error occurs. * same result a quorum error occurs.
*/ */
@ -747,21 +751,6 @@ static int64_t quorum_getlength(BlockDriverState *bs)
return result; return result;
} }
static void quorum_invalidate_cache(BlockDriverState *bs, Error **errp)
{
BDRVQuorumState *s = bs->opaque;
Error *local_err = NULL;
int i;
for (i = 0; i < s->num_children; i++) {
bdrv_invalidate_cache(s->children[i]->bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
}
static coroutine_fn int quorum_co_flush(BlockDriverState *bs) static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
{ {
BDRVQuorumState *s = bs->opaque; BDRVQuorumState *s = bs->opaque;
@ -898,9 +887,9 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
if (s->num_children < 2) { if (s->num_children < 1) {
error_setg(&local_err, error_setg(&local_err,
"Number of provided children must be greater than 1"); "Number of provided children must be 1 or more");
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
@ -964,6 +953,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
opened[i] = true; opened[i] = true;
} }
s->next_child_index = s->num_children;
g_free(opened); g_free(opened);
goto exit; goto exit;
@ -1020,6 +1010,72 @@ static void quorum_attach_aio_context(BlockDriverState *bs,
} }
} }
static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
Error **errp)
{
BDRVQuorumState *s = bs->opaque;
BdrvChild *child;
char indexstr[32];
int ret;
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
s->next_child_index == UINT_MAX) {
error_setg(errp, "Too many children");
return;
}
ret = snprintf(indexstr, 32, "children.%u", s->next_child_index);
if (ret < 0 || ret >= 32) {
error_setg(errp, "cannot generate child name");
return;
}
s->next_child_index++;
bdrv_drained_begin(bs);
/* We can safely add the child now */
bdrv_ref(child_bs);
child = bdrv_attach_child(bs, child_bs, indexstr, &child_format);
s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
s->children[s->num_children++] = child;
bdrv_drained_end(bs);
}
static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
Error **errp)
{
BDRVQuorumState *s = bs->opaque;
int i;
for (i = 0; i < s->num_children; i++) {
if (s->children[i] == child) {
break;
}
}
/* we have checked it in bdrv_del_child() */
assert(i < s->num_children);
if (s->num_children <= s->threshold) {
error_setg(errp,
"The number of children cannot be lower than the vote threshold %d",
s->threshold);
return;
}
bdrv_drained_begin(bs);
/* We can safely remove this child now */
memmove(&s->children[i], &s->children[i + 1],
(s->num_children - i - 1) * sizeof(BdrvChild *));
s->children = g_renew(BdrvChild *, s->children, --s->num_children);
bdrv_unref_child(bs, child);
bdrv_drained_end(bs);
}
static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
{ {
BDRVQuorumState *s = bs->opaque; BDRVQuorumState *s = bs->opaque;
@ -1070,11 +1126,13 @@ static BlockDriver bdrv_quorum = {
.bdrv_aio_readv = quorum_aio_readv, .bdrv_aio_readv = quorum_aio_readv,
.bdrv_aio_writev = quorum_aio_writev, .bdrv_aio_writev = quorum_aio_writev,
.bdrv_invalidate_cache = quorum_invalidate_cache,
.bdrv_detach_aio_context = quorum_detach_aio_context, .bdrv_detach_aio_context = quorum_detach_aio_context,
.bdrv_attach_aio_context = quorum_attach_aio_context, .bdrv_attach_aio_context = quorum_attach_aio_context,
.bdrv_add_child = quorum_add_child,
.bdrv_del_child = quorum_del_child,
.is_filter = true, .is_filter = true,
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
}; };

View File

@ -35,15 +35,16 @@
/* linux-aio.c - Linux native implementation */ /* linux-aio.c - Linux native implementation */
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
void *laio_init(void); typedef struct LinuxAioState LinuxAioState;
void laio_cleanup(void *s); LinuxAioState *laio_init(void);
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, void laio_cleanup(LinuxAioState *s);
BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque, int type); BlockCompletionFunc *cb, void *opaque, int type);
void laio_detach_aio_context(void *s, AioContext *old_context); void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
void laio_attach_aio_context(void *s, AioContext *new_context); void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
void laio_io_plug(BlockDriverState *bs, void *aio_ctx); void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug); void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s);
#endif #endif
#ifdef _WIN32 #ifdef _WIN32

View File

@ -139,7 +139,7 @@ typedef struct BDRVRawState {
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
int use_aio; int use_aio;
void *aio_ctx; LinuxAioState *aio_ctx;
#endif #endif
#ifdef CONFIG_XFS #ifdef CONFIG_XFS
bool is_xfs:1; bool is_xfs:1;
@ -398,7 +398,7 @@ static void raw_attach_aio_context(BlockDriverState *bs,
} }
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
static int raw_set_aio(void **aio_ctx, int *use_aio, int bdrv_flags) static int raw_set_aio(LinuxAioState **aio_ctx, int *use_aio, int bdrv_flags)
{ {
int ret = -1; int ret = -1;
assert(aio_ctx != NULL); assert(aio_ctx != NULL);
@ -517,6 +517,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->has_discard = true; s->has_discard = true;
s->has_write_zeroes = true; s->has_write_zeroes = true;
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) { if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
s->needs_alignment = true; s->needs_alignment = true;
} }
@ -1345,17 +1346,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
if (s->use_aio) { if (s->use_aio) {
laio_io_unplug(bs, s->aio_ctx, true); laio_io_unplug(bs, s->aio_ctx);
}
#endif
}
static void raw_aio_flush_io_queue(BlockDriverState *bs)
{
#ifdef CONFIG_LINUX_AIO
BDRVRawState *s = bs->opaque;
if (s->use_aio) {
laio_io_unplug(bs, s->aio_ctx, false);
} }
#endif #endif
} }
@ -1949,7 +1940,6 @@ BlockDriver bdrv_file = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2398,7 +2388,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2528,7 +2517,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2664,7 +2652,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,

View File

@ -105,8 +105,8 @@ raw_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
} }
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_do_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE, ret = bdrv_co_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE,
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags); nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
fail: fail:
if (qiov == &local_qiov) { if (qiov == &local_qiov) {
@ -116,13 +116,6 @@ fail:
return ret; return ret;
} }
static int coroutine_fn
raw_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov)
{
return raw_co_writev_flags(bs, sector_num, nb_sectors, qiov, 0);
}
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
int64_t sector_num, int64_t sector_num,
int nb_sectors, int *pnum, int nb_sectors, int *pnum,
@ -211,6 +204,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
bs->sg = bs->file->bs->sg; bs->sg = bs->file->bs->sg;
bs->supported_write_flags = BDRV_REQ_FUA;
bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP;
if (bs->probed && !bdrv_is_read_only(bs)) { if (bs->probed && !bdrv_is_read_only(bs)) {
fprintf(stderr, fprintf(stderr,
@ -256,9 +251,7 @@ BlockDriver bdrv_raw = {
.bdrv_close = &raw_close, .bdrv_close = &raw_close,
.bdrv_create = &raw_create, .bdrv_create = &raw_create,
.bdrv_co_readv = &raw_co_readv, .bdrv_co_readv = &raw_co_readv,
.bdrv_co_writev = &raw_co_writev,
.bdrv_co_writev_flags = &raw_co_writev_flags, .bdrv_co_writev_flags = &raw_co_writev_flags,
.supported_write_flags = BDRV_REQ_FUA,
.bdrv_co_write_zeroes = &raw_co_write_zeroes, .bdrv_co_write_zeroes = &raw_co_write_zeroes,
.bdrv_co_discard = &raw_co_discard, .bdrv_co_discard = &raw_co_discard,
.bdrv_co_get_block_status = &raw_co_get_block_status, .bdrv_co_get_block_status = &raw_co_get_block_status,

View File

@ -294,13 +294,16 @@ static inline size_t count_data_objs(const struct SheepdogInode *inode)
#undef DPRINTF #undef DPRINTF
#ifdef DEBUG_SDOG #ifdef DEBUG_SDOG
#define DPRINTF(fmt, args...) \ #define DEBUG_SDOG_PRINT 1
do { \
fprintf(stdout, "%s %d: " fmt, __func__, __LINE__, ##args); \
} while (0)
#else #else
#define DPRINTF(fmt, args...) #define DEBUG_SDOG_PRINT 0
#endif #endif
#define DPRINTF(fmt, args...) \
do { \
if (DEBUG_SDOG_PRINT) { \
fprintf(stderr, "%s %d: " fmt, __func__, __LINE__, ##args); \
} \
} while (0)
typedef struct SheepdogAIOCB SheepdogAIOCB; typedef struct SheepdogAIOCB SheepdogAIOCB;
@ -1678,7 +1681,7 @@ static int sd_prealloc(const char *filename, Error **errp)
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
ret = blk_pwrite(blk, idx * buf_size, buf, buf_size); ret = blk_pwrite(blk, idx * buf_size, buf, buf_size, 0);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }

View File

@ -219,6 +219,10 @@ static bool throttle_group_schedule_timer(BlockDriverState *bs,
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
bool must_wait; bool must_wait;
if (bs->io_limits_disabled) {
return false;
}
/* Check if any of the timers in this group is already armed */ /* Check if any of the timers in this group is already armed */
if (tg->any_timer_armed[is_write]) { if (tg->any_timer_armed[is_write]) {
return true; return true;
@ -313,6 +317,17 @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs,
qemu_mutex_unlock(&tg->lock); qemu_mutex_unlock(&tg->lock);
} }
void throttle_group_restart_bs(BlockDriverState *bs)
{
int i;
for (i = 0; i < 2; i++) {
while (qemu_co_enter_next(&bs->throttled_reqs[i])) {
;
}
}
}
/* Update the throttle configuration for a particular group. Similar /* Update the throttle configuration for a particular group. Similar
* to throttle_config(), but guarantees atomicity within the * to throttle_config(), but guarantees atomicity within the
* throttling group. * throttling group.
@ -335,6 +350,9 @@ void throttle_group_config(BlockDriverState *bs, ThrottleConfig *cfg)
} }
throttle_config(ts, tt, cfg); throttle_config(ts, tt, cfg);
qemu_mutex_unlock(&tg->lock); qemu_mutex_unlock(&tg->lock);
qemu_co_enter_next(&bs->throttled_reqs[0]);
qemu_co_enter_next(&bs->throttled_reqs[1]);
} }
/* Get the throttle configuration from a particular group. Similar to /* Get the throttle configuration from a particular group. Similar to

View File

@ -557,98 +557,109 @@ static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs,
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset; return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
} }
static int vdi_co_read(BlockDriverState *bs, static int coroutine_fn
int64_t sector_num, uint8_t *buf, int nb_sectors) vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVVdiState *s = bs->opaque; BDRVVdiState *s = bs->opaque;
QEMUIOVector local_qiov;
uint32_t bmap_entry; uint32_t bmap_entry;
uint32_t block_index; uint32_t block_index;
uint32_t sector_in_block; uint32_t offset_in_block;
uint32_t n_sectors; uint32_t n_bytes;
uint64_t bytes_done = 0;
int ret = 0; int ret = 0;
logout("\n"); logout("\n");
while (ret >= 0 && nb_sectors > 0) { qemu_iovec_init(&local_qiov, qiov->niov);
block_index = sector_num / s->block_sectors;
sector_in_block = sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
if (n_sectors > nb_sectors) {
n_sectors = nb_sectors;
}
logout("will read %u sectors starting at sector %" PRIu64 "\n", while (ret >= 0 && bytes > 0) {
n_sectors, sector_num); block_index = offset / s->block_size;
offset_in_block = offset % s->block_size;
n_bytes = MIN(bytes, s->block_size - offset_in_block);
logout("will read %u bytes starting at offset %" PRIu64 "\n",
n_bytes, offset);
/* prepare next AIO request */ /* prepare next AIO request */
bmap_entry = le32_to_cpu(s->bmap[block_index]); bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) { if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */ /* Block not allocated, return zeros, no need to wait. */
memset(buf, 0, n_sectors * SECTOR_SIZE); qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
ret = 0; ret = 0;
} else { } else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE + uint64_t data_offset = s->header.offset_data +
(uint64_t)bmap_entry * s->block_sectors + (uint64_t)bmap_entry * s->block_size +
sector_in_block; offset_in_block;
ret = bdrv_read(bs->file->bs, offset, buf, n_sectors);
}
logout("%u sectors read\n", n_sectors);
nb_sectors -= n_sectors; qemu_iovec_reset(&local_qiov);
sector_num += n_sectors; qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
buf += n_sectors * SECTOR_SIZE;
ret = bdrv_co_preadv(bs->file->bs, data_offset, n_bytes,
&local_qiov, 0);
}
logout("%u bytes read\n", n_bytes);
bytes -= n_bytes;
offset += n_bytes;
bytes_done += n_bytes;
} }
qemu_iovec_destroy(&local_qiov);
return ret; return ret;
} }
static int vdi_co_write(BlockDriverState *bs, static int coroutine_fn
int64_t sector_num, const uint8_t *buf, int nb_sectors) vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVVdiState *s = bs->opaque; BDRVVdiState *s = bs->opaque;
QEMUIOVector local_qiov;
uint32_t bmap_entry; uint32_t bmap_entry;
uint32_t block_index; uint32_t block_index;
uint32_t sector_in_block; uint32_t offset_in_block;
uint32_t n_sectors; uint32_t n_bytes;
uint32_t bmap_first = VDI_UNALLOCATED; uint32_t bmap_first = VDI_UNALLOCATED;
uint32_t bmap_last = VDI_UNALLOCATED; uint32_t bmap_last = VDI_UNALLOCATED;
uint8_t *block = NULL; uint8_t *block = NULL;
uint64_t bytes_done = 0;
int ret = 0; int ret = 0;
logout("\n"); logout("\n");
while (ret >= 0 && nb_sectors > 0) { qemu_iovec_init(&local_qiov, qiov->niov);
block_index = sector_num / s->block_sectors;
sector_in_block = sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
if (n_sectors > nb_sectors) {
n_sectors = nb_sectors;
}
logout("will write %u sectors starting at sector %" PRIu64 "\n", while (ret >= 0 && bytes > 0) {
n_sectors, sector_num); block_index = offset / s->block_size;
offset_in_block = offset % s->block_size;
n_bytes = MIN(bytes, s->block_size - offset_in_block);
logout("will write %u bytes starting at offset %" PRIu64 "\n",
n_bytes, offset);
/* prepare next AIO request */ /* prepare next AIO request */
bmap_entry = le32_to_cpu(s->bmap[block_index]); bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) { if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Allocate new block and write to it. */ /* Allocate new block and write to it. */
uint64_t offset; uint64_t data_offset;
bmap_entry = s->header.blocks_allocated; bmap_entry = s->header.blocks_allocated;
s->bmap[block_index] = cpu_to_le32(bmap_entry); s->bmap[block_index] = cpu_to_le32(bmap_entry);
s->header.blocks_allocated++; s->header.blocks_allocated++;
offset = s->header.offset_data / SECTOR_SIZE + data_offset = s->header.offset_data +
(uint64_t)bmap_entry * s->block_sectors; (uint64_t)bmap_entry * s->block_size;
if (block == NULL) { if (block == NULL) {
block = g_malloc(s->block_size); block = g_malloc(s->block_size);
bmap_first = block_index; bmap_first = block_index;
} }
bmap_last = block_index; bmap_last = block_index;
/* Copy data to be written to new block and zero unused parts. */ /* Copy data to be written to new block and zero unused parts. */
memset(block, 0, sector_in_block * SECTOR_SIZE); memset(block, 0, offset_in_block);
memcpy(block + sector_in_block * SECTOR_SIZE, qemu_iovec_to_buf(qiov, bytes_done, block + offset_in_block,
buf, n_sectors * SECTOR_SIZE); n_bytes);
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0, memset(block + offset_in_block + n_bytes, 0,
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE); s->block_size - n_bytes - offset_in_block);
/* Note that this coroutine does not yield anywhere from reading the /* Note that this coroutine does not yield anywhere from reading the
* bmap entry until here, so in regards to all the coroutines trying * bmap entry until here, so in regards to all the coroutines trying
@ -658,12 +669,12 @@ static int vdi_co_write(BlockDriverState *bs,
* acquire the lock and thus the padded cluster is written before * acquire the lock and thus the padded cluster is written before
* the other coroutines can write to the affected area. */ * the other coroutines can write to the affected area. */
qemu_co_mutex_lock(&s->write_lock); qemu_co_mutex_lock(&s->write_lock);
ret = bdrv_write(bs->file->bs, offset, block, s->block_sectors); ret = bdrv_pwrite(bs->file->bs, data_offset, block, s->block_size);
qemu_co_mutex_unlock(&s->write_lock); qemu_co_mutex_unlock(&s->write_lock);
} else { } else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE + uint64_t data_offset = s->header.offset_data +
(uint64_t)bmap_entry * s->block_sectors + (uint64_t)bmap_entry * s->block_size +
sector_in_block; offset_in_block;
qemu_co_mutex_lock(&s->write_lock); qemu_co_mutex_lock(&s->write_lock);
/* This lock is only used to make sure the following write operation /* This lock is only used to make sure the following write operation
* is executed after the write issued by the coroutine allocating * is executed after the write issued by the coroutine allocating
@ -674,16 +685,23 @@ static int vdi_co_write(BlockDriverState *bs,
* that that write operation has returned (there may be other writes * that that write operation has returned (there may be other writes
* in flight, but they do not concern this very operation). */ * in flight, but they do not concern this very operation). */
qemu_co_mutex_unlock(&s->write_lock); qemu_co_mutex_unlock(&s->write_lock);
ret = bdrv_write(bs->file->bs, offset, buf, n_sectors);
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
ret = bdrv_co_pwritev(bs->file->bs, data_offset, n_bytes,
&local_qiov, 0);
} }
nb_sectors -= n_sectors; bytes -= n_bytes;
sector_num += n_sectors; offset += n_bytes;
buf += n_sectors * SECTOR_SIZE; bytes_done += n_bytes;
logout("%u sectors written\n", n_sectors); logout("%u bytes written\n", n_bytes);
} }
qemu_iovec_destroy(&local_qiov);
logout("finished data write\n"); logout("finished data write\n");
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -694,6 +712,7 @@ static int vdi_co_write(BlockDriverState *bs,
VdiHeader *header = (VdiHeader *) block; VdiHeader *header = (VdiHeader *) block;
uint8_t *base; uint8_t *base;
uint64_t offset; uint64_t offset;
uint32_t n_sectors;
logout("now writing modified header\n"); logout("now writing modified header\n");
assert(VDI_IS_ALLOCATED(bmap_first)); assert(VDI_IS_ALLOCATED(bmap_first));
@ -808,7 +827,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
vdi_header_print(&header); vdi_header_print(&header);
#endif #endif
vdi_header_to_le(&header); vdi_header_to_le(&header);
ret = blk_pwrite(blk, offset, &header, sizeof(header)); ret = blk_pwrite(blk, offset, &header, sizeof(header), 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Error writing header to %s", filename); error_setg(errp, "Error writing header to %s", filename);
goto exit; goto exit;
@ -829,7 +848,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
bmap[i] = VDI_UNALLOCATED; bmap[i] = VDI_UNALLOCATED;
} }
} }
ret = blk_pwrite(blk, offset, bmap, bmap_size); ret = blk_pwrite(blk, offset, bmap, bmap_size, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Error writing bmap to %s", filename); error_setg(errp, "Error writing bmap to %s", filename);
goto exit; goto exit;
@ -903,9 +922,9 @@ static BlockDriver bdrv_vdi = {
.bdrv_co_get_block_status = vdi_co_get_block_status, .bdrv_co_get_block_status = vdi_co_get_block_status,
.bdrv_make_empty = vdi_make_empty, .bdrv_make_empty = vdi_make_empty,
.bdrv_read = vdi_co_read, .bdrv_co_preadv = vdi_co_preadv,
#if defined(CONFIG_VDI_WRITE) #if defined(CONFIG_VDI_WRITE)
.bdrv_write = vdi_co_write, .bdrv_co_pwritev = vdi_co_pwritev,
#endif #endif
.bdrv_get_info = vdi_get_info, .bdrv_get_info = vdi_get_info,

View File

@ -1856,13 +1856,14 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL, creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL,
&creator_items, NULL); &creator_items, NULL);
signature = cpu_to_le64(VHDX_FILE_SIGNATURE); signature = cpu_to_le64(VHDX_FILE_SIGNATURE);
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature)); ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature),
0);
if (ret < 0) { if (ret < 0) {
goto delete_and_exit; goto delete_and_exit;
} }
if (creator) { if (creator) {
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature), ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
creator, creator_items * sizeof(gunichar2)); creator, creator_items * sizeof(gunichar2), 0);
if (ret < 0) { if (ret < 0) {
goto delete_and_exit; goto delete_and_exit;
} }

View File

@ -1016,27 +1016,26 @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
*/ */
static int get_whole_cluster(BlockDriverState *bs, static int get_whole_cluster(BlockDriverState *bs,
VmdkExtent *extent, VmdkExtent *extent,
uint64_t cluster_sector_num, uint64_t cluster_offset,
uint64_t sector_num, uint64_t offset,
uint64_t skip_start_sector, uint64_t skip_start_bytes,
uint64_t skip_end_sector) uint64_t skip_end_bytes)
{ {
int ret = VMDK_OK; int ret = VMDK_OK;
int64_t cluster_bytes; int64_t cluster_bytes;
uint8_t *whole_grain; uint8_t *whole_grain;
/* For COW, align request sector_num to cluster start */ /* For COW, align request sector_num to cluster start */
sector_num = QEMU_ALIGN_DOWN(sector_num, extent->cluster_sectors);
cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS;
offset = QEMU_ALIGN_DOWN(offset, cluster_bytes);
whole_grain = qemu_blockalign(bs, cluster_bytes); whole_grain = qemu_blockalign(bs, cluster_bytes);
if (!bs->backing) { if (!bs->backing) {
memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS); memset(whole_grain, 0, skip_start_bytes);
memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0, memset(whole_grain + skip_end_bytes, 0, cluster_bytes - skip_end_bytes);
cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS));
} }
assert(skip_end_sector <= extent->cluster_sectors); assert(skip_end_bytes <= cluster_bytes);
/* we will be here if it's first write on non-exist grain(cluster). /* we will be here if it's first write on non-exist grain(cluster).
* try to read from parent image, if exist */ * try to read from parent image, if exist */
if (bs->backing && !vmdk_is_cid_valid(bs)) { if (bs->backing && !vmdk_is_cid_valid(bs)) {
@ -1045,42 +1044,43 @@ static int get_whole_cluster(BlockDriverState *bs,
} }
/* Read backing data before skip range */ /* Read backing data before skip range */
if (skip_start_sector > 0) { if (skip_start_bytes > 0) {
if (bs->backing) { if (bs->backing) {
ret = bdrv_read(bs->backing->bs, sector_num, ret = bdrv_pread(bs->backing->bs, offset, whole_grain,
whole_grain, skip_start_sector); skip_start_bytes);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
ret = bdrv_write(extent->file->bs, cluster_sector_num, whole_grain, ret = bdrv_pwrite(extent->file->bs, cluster_offset, whole_grain,
skip_start_sector); skip_start_bytes);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
/* Read backing data after skip range */ /* Read backing data after skip range */
if (skip_end_sector < extent->cluster_sectors) { if (skip_end_bytes < cluster_bytes) {
if (bs->backing) { if (bs->backing) {
ret = bdrv_read(bs->backing->bs, sector_num + skip_end_sector, ret = bdrv_pread(bs->backing->bs, offset + skip_end_bytes,
whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), whole_grain + skip_end_bytes,
extent->cluster_sectors - skip_end_sector); cluster_bytes - skip_end_bytes);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
ret = bdrv_write(extent->file->bs, cluster_sector_num + skip_end_sector, ret = bdrv_pwrite(extent->file->bs, cluster_offset + skip_end_bytes,
whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), whole_grain + skip_end_bytes,
extent->cluster_sectors - skip_end_sector); cluster_bytes - skip_end_bytes);
if (ret < 0) { if (ret < 0) {
ret = VMDK_ERROR; ret = VMDK_ERROR;
goto exit; goto exit;
} }
} }
ret = VMDK_OK;
exit: exit:
qemu_vfree(whole_grain); qemu_vfree(whole_grain);
return ret; return ret;
@ -1142,8 +1142,8 @@ static int get_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
bool allocate, bool allocate,
uint64_t *cluster_offset, uint64_t *cluster_offset,
uint64_t skip_start_sector, uint64_t skip_start_bytes,
uint64_t skip_end_sector) uint64_t skip_end_bytes)
{ {
unsigned int l1_index, l2_offset, l2_index; unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j; int min_index, i, j;
@ -1230,10 +1230,8 @@ static int get_cluster_offset(BlockDriverState *bs,
* This problem may occur because of insufficient space on host disk * This problem may occur because of insufficient space on host disk
* or inappropriate VM shutdown. * or inappropriate VM shutdown.
*/ */
ret = get_whole_cluster(bs, extent, ret = get_whole_cluster(bs, extent, cluster_sector * BDRV_SECTOR_SIZE,
cluster_sector, offset, skip_start_bytes, skip_end_bytes);
offset >> BDRV_SECTOR_BITS,
skip_start_sector, skip_end_sector);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -1259,15 +1257,26 @@ static VmdkExtent *find_extent(BDRVVmdkState *s,
return NULL; return NULL;
} }
static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent,
int64_t offset)
{
uint64_t offset_in_cluster, extent_begin_offset, extent_relative_offset;
uint64_t cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE;
extent_begin_offset =
(extent->end_sector - extent->sectors) * BDRV_SECTOR_SIZE;
extent_relative_offset = offset - extent_begin_offset;
offset_in_cluster = extent_relative_offset % cluster_size;
return offset_in_cluster;
}
static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent, static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent,
int64_t sector_num) int64_t sector_num)
{ {
uint64_t index_in_cluster, extent_begin_sector, extent_relative_sector_num; uint64_t offset;
offset = vmdk_find_offset_in_cluster(extent, sector_num * BDRV_SECTOR_SIZE);
extent_begin_sector = extent->end_sector - extent->sectors; return offset / BDRV_SECTOR_SIZE;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
return index_in_cluster;
} }
static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
@ -1319,38 +1328,57 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
} }
static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
int64_t offset_in_cluster, const uint8_t *buf, int64_t offset_in_cluster, QEMUIOVector *qiov,
int nb_sectors, int64_t sector_num) uint64_t qiov_offset, uint64_t n_bytes,
uint64_t offset)
{ {
int ret; int ret;
VmdkGrainMarker *data = NULL; VmdkGrainMarker *data = NULL;
uLongf buf_len; uLongf buf_len;
const uint8_t *write_buf = buf; QEMUIOVector local_qiov;
int write_len = nb_sectors * 512; struct iovec iov;
int64_t write_offset; int64_t write_offset;
int64_t write_end_sector; int64_t write_end_sector;
if (extent->compressed) { if (extent->compressed) {
void *compressed_data;
if (!extent->has_marker) { if (!extent->has_marker) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
buf_len = (extent->cluster_sectors << 9) * 2; buf_len = (extent->cluster_sectors << 9) * 2;
data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); data = g_malloc(buf_len + sizeof(VmdkGrainMarker));
if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK ||
buf_len == 0) { compressed_data = g_malloc(n_bytes);
qemu_iovec_to_buf(qiov, qiov_offset, compressed_data, n_bytes);
ret = compress(data->data, &buf_len, compressed_data, n_bytes);
g_free(compressed_data);
if (ret != Z_OK || buf_len == 0) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
data->lba = sector_num;
data->size = buf_len;
write_buf = (uint8_t *)data;
write_len = buf_len + sizeof(VmdkGrainMarker);
}
write_offset = cluster_offset + offset_in_cluster,
ret = bdrv_pwrite(extent->file->bs, write_offset, write_buf, write_len);
write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); data->lba = offset >> BDRV_SECTOR_BITS;
data->size = buf_len;
n_bytes = buf_len + sizeof(VmdkGrainMarker);
iov = (struct iovec) {
.iov_base = data,
.iov_len = n_bytes,
};
qemu_iovec_init_external(&local_qiov, &iov, 1);
} else {
qemu_iovec_init(&local_qiov, qiov->niov);
qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
}
write_offset = cluster_offset + offset_in_cluster,
ret = bdrv_co_pwritev(extent->file->bs, write_offset, n_bytes,
&local_qiov, 0);
write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE);
if (extent->compressed) { if (extent->compressed) {
extent->next_cluster_sector = write_end_sector; extent->next_cluster_sector = write_end_sector;
@ -1359,19 +1387,21 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
write_end_sector); write_end_sector);
} }
if (ret != write_len) { if (ret < 0) {
ret = ret < 0 ? ret : -EIO;
goto out; goto out;
} }
ret = 0; ret = 0;
out: out:
g_free(data); g_free(data);
if (!extent->compressed) {
qemu_iovec_destroy(&local_qiov);
}
return ret; return ret;
} }
static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
int64_t offset_in_cluster, uint8_t *buf, int64_t offset_in_cluster, QEMUIOVector *qiov,
int nb_sectors) int bytes)
{ {
int ret; int ret;
int cluster_bytes, buf_bytes; int cluster_bytes, buf_bytes;
@ -1383,14 +1413,13 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
if (!extent->compressed) { if (!extent->compressed) {
ret = bdrv_pread(extent->file->bs, ret = bdrv_co_preadv(extent->file->bs,
cluster_offset + offset_in_cluster, cluster_offset + offset_in_cluster, bytes,
buf, nb_sectors * 512); qiov, 0);
if (ret == nb_sectors * 512) { if (ret < 0) {
return 0; return ret;
} else {
return -EIO;
} }
return 0;
} }
cluster_bytes = extent->cluster_sectors * 512; cluster_bytes = extent->cluster_sectors * 512;
/* Read two clusters in case GrainMarker + compressed data > one cluster */ /* Read two clusters in case GrainMarker + compressed data > one cluster */
@ -1422,11 +1451,11 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
} }
if (offset_in_cluster < 0 || if (offset_in_cluster < 0 ||
offset_in_cluster + nb_sectors * 512 > buf_len) { offset_in_cluster + bytes > buf_len) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512); qemu_iovec_from_buf(qiov, 0, uncomp_buf + offset_in_cluster, bytes);
ret = 0; ret = 0;
out: out:
@ -1435,64 +1464,73 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
return ret; return ret;
} }
static int vmdk_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
int ret; int ret;
uint64_t n, index_in_cluster; uint64_t n_bytes, offset_in_cluster;
VmdkExtent *extent = NULL; VmdkExtent *extent = NULL;
QEMUIOVector local_qiov;
uint64_t cluster_offset; uint64_t cluster_offset;
uint64_t bytes_done = 0;
while (nb_sectors > 0) { qemu_iovec_init(&local_qiov, qiov->niov);
extent = find_extent(s, sector_num, extent); qemu_co_mutex_lock(&s->lock);
while (bytes > 0) {
extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent);
if (!extent) { if (!extent) {
return -EIO; ret = -EIO;
goto fail;
} }
ret = get_cluster_offset(bs, extent, NULL, ret = get_cluster_offset(bs, extent, NULL,
sector_num << 9, false, &cluster_offset, offset, false, &cluster_offset, 0, 0);
0, 0); offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
n = extent->cluster_sectors - index_in_cluster; n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
if (n > nb_sectors) { - offset_in_cluster);
n = nb_sectors;
}
if (ret != VMDK_OK) { if (ret != VMDK_OK) {
/* if not allocated, try to read from parent image, if exist */ /* if not allocated, try to read from parent image, if exist */
if (bs->backing && ret != VMDK_ZEROED) { if (bs->backing && ret != VMDK_ZEROED) {
if (!vmdk_is_cid_valid(bs)) { if (!vmdk_is_cid_valid(bs)) {
return -EINVAL; ret = -EINVAL;
goto fail;
} }
ret = bdrv_read(bs->backing->bs, sector_num, buf, n);
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
ret = bdrv_co_preadv(bs->backing->bs, offset, n_bytes,
&local_qiov, 0);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
} }
} else { } else {
memset(buf, 0, 512 * n); qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
} }
} else { } else {
ret = vmdk_read_extent(extent, qemu_iovec_reset(&local_qiov);
cluster_offset, index_in_cluster * 512, qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
buf, n);
ret = vmdk_read_extent(extent, cluster_offset, offset_in_cluster,
&local_qiov, n_bytes);
if (ret) { if (ret) {
return ret; goto fail;
} }
} }
nb_sectors -= n; bytes -= n_bytes;
sector_num += n; offset += n_bytes;
buf += n * 512; bytes_done += n_bytes;
} }
return 0;
}
static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, ret = 0;
uint8_t *buf, int nb_sectors) fail:
{
int ret;
BDRVVmdkState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = vmdk_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
qemu_iovec_destroy(&local_qiov);
return ret; return ret;
} }
@ -1506,38 +1544,38 @@ static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
* *
* Returns: error code with 0 for success. * Returns: error code with 0 for success.
*/ */
static int vmdk_write(BlockDriverState *bs, int64_t sector_num, static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
const uint8_t *buf, int nb_sectors, uint64_t bytes, QEMUIOVector *qiov,
bool zeroed, bool zero_dry_run) bool zeroed, bool zero_dry_run)
{ {
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent = NULL; VmdkExtent *extent = NULL;
int ret; int ret;
int64_t index_in_cluster, n; int64_t offset_in_cluster, n_bytes;
uint64_t cluster_offset; uint64_t cluster_offset;
uint64_t bytes_done = 0;
VmdkMetaData m_data; VmdkMetaData m_data;
if (sector_num > bs->total_sectors) { if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) {
error_report("Wrong offset: sector_num=0x%" PRIx64 error_report("Wrong offset: offset=0x%" PRIx64
" total_sectors=0x%" PRIx64, " total_sectors=0x%" PRIx64,
sector_num, bs->total_sectors); offset, bs->total_sectors);
return -EIO; return -EIO;
} }
while (nb_sectors > 0) { while (bytes > 0) {
extent = find_extent(s, sector_num, extent); extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent);
if (!extent) { if (!extent) {
return -EIO; return -EIO;
} }
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
n = extent->cluster_sectors - index_in_cluster; n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
if (n > nb_sectors) { - offset_in_cluster);
n = nb_sectors;
} ret = get_cluster_offset(bs, extent, &m_data, offset,
ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9,
!(extent->compressed || zeroed), !(extent->compressed || zeroed),
&cluster_offset, &cluster_offset, offset_in_cluster,
index_in_cluster, index_in_cluster + n); offset_in_cluster + n_bytes);
if (extent->compressed) { if (extent->compressed) {
if (ret == VMDK_OK) { if (ret == VMDK_OK) {
/* Refuse write to allocated cluster for streamOptimized */ /* Refuse write to allocated cluster for streamOptimized */
@ -1546,7 +1584,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
return -EIO; return -EIO;
} else { } else {
/* allocate */ /* allocate */
ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9, ret = get_cluster_offset(bs, extent, &m_data, offset,
true, &cluster_offset, 0, 0); true, &cluster_offset, 0, 0);
} }
} }
@ -1556,9 +1594,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
if (zeroed) { if (zeroed) {
/* Do zeroed write, buf is ignored */ /* Do zeroed write, buf is ignored */
if (extent->has_zero_grain && if (extent->has_zero_grain &&
index_in_cluster == 0 && offset_in_cluster == 0 &&
n >= extent->cluster_sectors) { n_bytes >= extent->cluster_sectors * BDRV_SECTOR_SIZE) {
n = extent->cluster_sectors; n_bytes = extent->cluster_sectors * BDRV_SECTOR_SIZE;
if (!zero_dry_run) { if (!zero_dry_run) {
/* update L2 tables */ /* update L2 tables */
if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED) if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED)
@ -1570,9 +1608,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
return -ENOTSUP; return -ENOTSUP;
} }
} else { } else {
ret = vmdk_write_extent(extent, ret = vmdk_write_extent(extent, cluster_offset, offset_in_cluster,
cluster_offset, index_in_cluster * 512, qiov, bytes_done, n_bytes, offset);
buf, n, sector_num);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -1585,9 +1622,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
} }
} }
} }
nb_sectors -= n; bytes -= n_bytes;
sector_num += n; offset += n_bytes;
buf += n * 512; bytes_done += n_bytes;
/* update CID on the first write every time the virtual disk is /* update CID on the first write every time the virtual disk is
* opened */ * opened */
@ -1602,25 +1639,65 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
return 0; return 0;
} }
static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
const uint8_t *buf, int nb_sectors) vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
int ret; int ret;
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false); ret = vmdk_pwritev(bs, offset, bytes, qiov, false, false);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
} }
typedef struct VmdkWriteCompressedCo {
BlockDriverState *bs;
int64_t sector_num;
const uint8_t *buf;
int nb_sectors;
int ret;
} VmdkWriteCompressedCo;
static void vmdk_co_write_compressed(void *opaque)
{
VmdkWriteCompressedCo *co = opaque;
QEMUIOVector local_qiov;
uint64_t offset = co->sector_num * BDRV_SECTOR_SIZE;
uint64_t bytes = co->nb_sectors * BDRV_SECTOR_SIZE;
struct iovec iov = (struct iovec) {
.iov_base = (uint8_t*) co->buf,
.iov_len = bytes,
};
qemu_iovec_init_external(&local_qiov, &iov, 1);
co->ret = vmdk_pwritev(co->bs, offset, bytes, &local_qiov, false, false);
}
static int vmdk_write_compressed(BlockDriverState *bs, static int vmdk_write_compressed(BlockDriverState *bs,
int64_t sector_num, int64_t sector_num,
const uint8_t *buf, const uint8_t *buf,
int nb_sectors) int nb_sectors)
{ {
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
if (s->num_extents == 1 && s->extents[0].compressed) { if (s->num_extents == 1 && s->extents[0].compressed) {
return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); Coroutine *co;
AioContext *aio_context = bdrv_get_aio_context(bs);
VmdkWriteCompressedCo data = {
.bs = bs,
.sector_num = sector_num,
.buf = buf,
.nb_sectors = nb_sectors,
.ret = -EINPROGRESS,
};
co = qemu_coroutine_create(vmdk_co_write_compressed);
qemu_coroutine_enter(co, &data);
while (data.ret == -EINPROGRESS) {
aio_poll(aio_context, true);
}
return data.ret;
} else { } else {
return -ENOTSUP; return -ENOTSUP;
} }
@ -1633,12 +1710,15 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
{ {
int ret; int ret;
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
uint64_t offset = sector_num * BDRV_SECTOR_SIZE;
uint64_t bytes = nb_sectors * BDRV_SECTOR_SIZE;
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
/* write zeroes could fail if sectors not aligned to cluster, test it with /* write zeroes could fail if sectors not aligned to cluster, test it with
* dry_run == true before really updating image */ * dry_run == true before really updating image */
ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); ret = vmdk_pwritev(bs, offset, bytes, NULL, true, true);
if (!ret) { if (!ret) {
ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); ret = vmdk_pwritev(bs, offset, bytes, NULL, true, false);
} }
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
@ -1728,12 +1808,12 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
header.check_bytes[3] = 0xa; header.check_bytes[3] = 0xa;
/* write all the data */ /* write all the data */
ret = blk_pwrite(blk, 0, &magic, sizeof(magic)); ret = blk_pwrite(blk, 0, &magic, sizeof(magic), 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, QERR_IO_ERROR); error_setg(errp, QERR_IO_ERROR);
goto exit; goto exit;
} }
ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header)); ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header), 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, QERR_IO_ERROR); error_setg(errp, QERR_IO_ERROR);
goto exit; goto exit;
@ -1753,7 +1833,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
gd_buf[i] = cpu_to_le32(tmp); gd_buf[i] = cpu_to_le32(tmp);
} }
ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE,
gd_buf, gd_buf_size); gd_buf, gd_buf_size, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, QERR_IO_ERROR); error_setg(errp, QERR_IO_ERROR);
goto exit; goto exit;
@ -1765,7 +1845,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
gd_buf[i] = cpu_to_le32(tmp); gd_buf[i] = cpu_to_le32(tmp);
} }
ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE,
gd_buf, gd_buf_size); gd_buf, gd_buf_size, 0);
if (ret < 0) { if (ret < 0) {
error_setg(errp, QERR_IO_ERROR); error_setg(errp, QERR_IO_ERROR);
goto exit; goto exit;
@ -1829,8 +1909,8 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
int64_t total_size = 0, filesize; int64_t total_size = 0, filesize;
char *adapter_type = NULL; char *adapter_type = NULL;
char *backing_file = NULL; char *backing_file = NULL;
char *hw_version = NULL;
char *fmt = NULL; char *fmt = NULL;
int flags = 0;
int ret = 0; int ret = 0;
bool flat, split, compress; bool flat, split, compress;
GString *ext_desc_lines; GString *ext_desc_lines;
@ -1861,7 +1941,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
"# The Disk Data Base\n" "# The Disk Data Base\n"
"#DDB\n" "#DDB\n"
"\n" "\n"
"ddb.virtualHWVersion = \"%d\"\n" "ddb.virtualHWVersion = \"%s\"\n"
"ddb.geometry.cylinders = \"%" PRId64 "\"\n" "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"%" PRIu32 "\"\n" "ddb.geometry.heads = \"%" PRIu32 "\"\n"
"ddb.geometry.sectors = \"63\"\n" "ddb.geometry.sectors = \"63\"\n"
@ -1878,8 +1958,20 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
BDRV_SECTOR_SIZE); BDRV_SECTOR_SIZE);
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) {
flags |= BLOCK_FLAG_COMPAT6; if (strcmp(hw_version, "undefined")) {
error_setg(errp,
"compat6 cannot be enabled with hwversion set");
ret = -EINVAL;
goto exit;
}
g_free(hw_version);
hw_version = g_strdup("6");
}
if (strcmp(hw_version, "undefined") == 0) {
g_free(hw_version);
hw_version = g_strdup("4");
} }
fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) {
@ -2001,7 +2093,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
fmt, fmt,
parent_desc_line, parent_desc_line,
ext_desc_lines->str, ext_desc_lines->str,
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), hw_version,
total_size / total_size /
(int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE),
number_heads, number_heads,
@ -2028,7 +2120,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(new_blk, true); blk_set_allow_write_beyond_eof(new_blk, true);
ret = blk_pwrite(new_blk, desc_offset, desc, desc_len); ret = blk_pwrite(new_blk, desc_offset, desc, desc_len, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write description"); error_setg_errno(errp, -ret, "Could not write description");
goto exit; goto exit;
@ -2047,6 +2139,7 @@ exit:
} }
g_free(adapter_type); g_free(adapter_type);
g_free(backing_file); g_free(backing_file);
g_free(hw_version);
g_free(fmt); g_free(fmt);
g_free(desc); g_free(desc);
g_free(path); g_free(path);
@ -2297,6 +2390,12 @@ static QemuOptsList vmdk_create_opts = {
.help = "VMDK version 6 image", .help = "VMDK version 6 image",
.def_value_str = "off" .def_value_str = "off"
}, },
{
.name = BLOCK_OPT_HWVERSION,
.type = QEMU_OPT_STRING,
.help = "VMDK hardware version",
.def_value_str = "undefined"
},
{ {
.name = BLOCK_OPT_SUBFMT, .name = BLOCK_OPT_SUBFMT,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
@ -2321,8 +2420,8 @@ static BlockDriver bdrv_vmdk = {
.bdrv_open = vmdk_open, .bdrv_open = vmdk_open,
.bdrv_check = vmdk_check, .bdrv_check = vmdk_check,
.bdrv_reopen_prepare = vmdk_reopen_prepare, .bdrv_reopen_prepare = vmdk_reopen_prepare,
.bdrv_read = vmdk_co_read, .bdrv_co_preadv = vmdk_co_preadv,
.bdrv_write = vmdk_co_write, .bdrv_co_pwritev = vmdk_co_pwritev,
.bdrv_write_compressed = vmdk_write_compressed, .bdrv_write_compressed = vmdk_write_compressed,
.bdrv_co_write_zeroes = vmdk_co_write_zeroes, .bdrv_co_write_zeroes = vmdk_co_write_zeroes,
.bdrv_close = vmdk_close, .bdrv_close = vmdk_close,

View File

@ -454,22 +454,21 @@ static int vpc_reopen_prepare(BDRVReopenState *state,
* The parameter write must be 1 if the offset will be used for a write * The parameter write must be 1 if the offset will be used for a write
* operation (the block bitmaps is updated then), 0 otherwise. * operation (the block bitmaps is updated then), 0 otherwise.
*/ */
static inline int64_t get_sector_offset(BlockDriverState *bs, static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
int64_t sector_num, int write) bool write)
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset; uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index; uint32_t pagetable_index, offset_in_block;
pagetable_index = offset / s->block_size; pagetable_index = offset / s->block_size;
pageentry_index = (offset % s->block_size) / 512; offset_in_block = offset % s->block_size;
if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff) if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
return -1; /* not allocated */ return -1; /* not allocated */
bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index]; bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index); block_offset = bitmap_offset + s->bitmap_size + offset_in_block;
/* We must ensure that we don't write to any sectors which are marked as /* We must ensure that we don't write to any sectors which are marked as
unused in the bitmap. We get away with setting all bits in the block unused in the bitmap. We get away with setting all bits in the block
@ -487,6 +486,12 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
return block_offset; return block_offset;
} }
static inline int64_t get_sector_offset(BlockDriverState *bs,
int64_t sector_num, bool write)
{
return get_image_offset(bs, sector_num * BDRV_SECTOR_SIZE, write);
}
/* /*
* Writes the footer to the end of the image file. This is needed when the * Writes the footer to the end of the image file. This is needed when the
* file grows as it overwrites the old footer * file grows as it overwrites the old footer
@ -513,7 +518,7 @@ static int rewrite_footer(BlockDriverState* bs)
* *
* Returns the sectors' offset in the image file on success and < 0 on error * Returns the sectors' offset in the image file on success and < 0 on error
*/ */
static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
int64_t bat_offset; int64_t bat_offset;
@ -522,14 +527,13 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
uint8_t bitmap[s->bitmap_size]; uint8_t bitmap[s->bitmap_size];
/* Check if sector_num is valid */ /* Check if sector_num is valid */
if ((sector_num < 0) || (sector_num > bs->total_sectors)) if ((offset < 0) || (offset > bs->total_sectors * BDRV_SECTOR_SIZE)) {
return -1; return -EINVAL;
}
/* Write entry into in-memory BAT */ /* Write entry into in-memory BAT */
index = (sector_num * 512) / s->block_size; index = offset / s->block_size;
if (s->pagetable[index] != 0xFFFFFFFF) assert(s->pagetable[index] == 0xFFFFFFFF);
return -1;
s->pagetable[index] = s->free_data_block_offset / 512; s->pagetable[index] = s->free_data_block_offset / 512;
/* Initialize the block's bitmap */ /* Initialize the block's bitmap */
@ -553,11 +557,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
if (ret < 0) if (ret < 0)
goto fail; goto fail;
return get_sector_offset(bs, sector_num, 0); return get_image_offset(bs, offset, false);
fail: fail:
s->free_data_block_offset -= (s->block_size + s->bitmap_size); s->free_data_block_offset -= (s->block_size + s->bitmap_size);
return -1; return ret;
} }
static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@ -573,104 +577,105 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0; return 0;
} }
static int vpc_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
int ret; int ret;
int64_t offset; int64_t image_offset;
int64_t sectors, sectors_per_block; int64_t n_bytes;
int64_t bytes_done = 0;
VHDFooter *footer = (VHDFooter *) s->footer_buf; VHDFooter *footer = (VHDFooter *) s->footer_buf;
QEMUIOVector local_qiov;
if (be32_to_cpu(footer->type) == VHD_FIXED) { if (be32_to_cpu(footer->type) == VHD_FIXED) {
return bdrv_read(bs->file->bs, sector_num, buf, nb_sectors); return bdrv_co_preadv(bs->file->bs, offset, bytes, qiov, 0);
} }
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 0);
sectors_per_block = s->block_size >> BDRV_SECTOR_BITS; qemu_co_mutex_lock(&s->lock);
sectors = sectors_per_block - (sector_num % sectors_per_block); qemu_iovec_init(&local_qiov, qiov->niov);
if (sectors > nb_sectors) {
sectors = nb_sectors;
}
if (offset == -1) { while (bytes > 0) {
memset(buf, 0, sectors * BDRV_SECTOR_SIZE); image_offset = get_image_offset(bs, offset, false);
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
} else { } else {
ret = bdrv_pread(bs->file->bs, offset, buf, qemu_iovec_reset(&local_qiov);
sectors * BDRV_SECTOR_SIZE); qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
if (ret != sectors * BDRV_SECTOR_SIZE) {
return -1; ret = bdrv_co_preadv(bs->file->bs, image_offset, n_bytes,
&local_qiov, 0);
if (ret < 0) {
goto fail;
} }
} }
nb_sectors -= sectors; bytes -= n_bytes;
sector_num += sectors; offset += n_bytes;
buf += sectors * BDRV_SECTOR_SIZE; bytes_done += n_bytes;
} }
return 0;
}
static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num, ret = 0;
uint8_t *buf, int nb_sectors) fail:
{ qemu_iovec_destroy(&local_qiov);
int ret;
BDRVVPCState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock);
ret = vpc_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
} }
static int vpc_write(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
const uint8_t *buf, int nb_sectors) vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
int64_t offset; int64_t image_offset;
int64_t sectors, sectors_per_block; int64_t n_bytes;
int64_t bytes_done = 0;
int ret; int ret;
VHDFooter *footer = (VHDFooter *) s->footer_buf; VHDFooter *footer = (VHDFooter *) s->footer_buf;
QEMUIOVector local_qiov;
if (be32_to_cpu(footer->type) == VHD_FIXED) { if (be32_to_cpu(footer->type) == VHD_FIXED) {
return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors); return bdrv_co_pwritev(bs->file->bs, offset, bytes, qiov, 0);
}
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 1);
sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
sectors = sectors_per_block - (sector_num % sectors_per_block);
if (sectors > nb_sectors) {
sectors = nb_sectors;
}
if (offset == -1) {
offset = alloc_block(bs, sector_num);
if (offset < 0)
return -1;
}
ret = bdrv_pwrite(bs->file->bs, offset, buf,
sectors * BDRV_SECTOR_SIZE);
if (ret != sectors * BDRV_SECTOR_SIZE) {
return -1;
}
nb_sectors -= sectors;
sector_num += sectors;
buf += sectors * BDRV_SECTOR_SIZE;
} }
return 0;
}
static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int ret;
BDRVVPCState *s = bs->opaque;
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
ret = vpc_write(bs, sector_num, buf, nb_sectors); qemu_iovec_init(&local_qiov, qiov->niov);
while (bytes > 0) {
image_offset = get_image_offset(bs, offset, true);
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
image_offset = alloc_block(bs, offset);
if (image_offset < 0) {
ret = image_offset;
goto fail;
}
}
qemu_iovec_reset(&local_qiov);
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
ret = bdrv_co_pwritev(bs->file->bs, image_offset, n_bytes,
&local_qiov, 0);
if (ret < 0) {
goto fail;
}
bytes -= n_bytes;
offset += n_bytes;
bytes_done += n_bytes;
}
ret = 0;
fail:
qemu_iovec_destroy(&local_qiov);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
return ret; return ret;
} }
@ -783,13 +788,13 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
block_size = 0x200000; block_size = 0x200000;
num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512); num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
ret = blk_pwrite(blk, offset, buf, HEADER_SIZE); ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
offset = 1536 + ((num_bat_entries * 4 + 511) & ~511); offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
ret = blk_pwrite(blk, offset, buf, HEADER_SIZE); ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -799,7 +804,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
memset(buf, 0xFF, 512); memset(buf, 0xFF, 512);
for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) { for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
ret = blk_pwrite(blk, offset, buf, 512); ret = blk_pwrite(blk, offset, buf, 512, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -826,7 +831,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
/* Write the header */ /* Write the header */
offset = 512; offset = 512;
ret = blk_pwrite(blk, offset, buf, 1024); ret = blk_pwrite(blk, offset, buf, 1024, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -848,7 +853,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
return ret; return ret;
} }
ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE); ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -1056,8 +1061,8 @@ static BlockDriver bdrv_vpc = {
.bdrv_reopen_prepare = vpc_reopen_prepare, .bdrv_reopen_prepare = vpc_reopen_prepare,
.bdrv_create = vpc_create, .bdrv_create = vpc_create,
.bdrv_read = vpc_co_read, .bdrv_co_preadv = vpc_co_preadv,
.bdrv_write = vpc_co_write, .bdrv_co_pwritev = vpc_co_pwritev,
.bdrv_co_get_block_status = vpc_co_get_block_status, .bdrv_co_get_block_status = vpc_co_get_block_status,
.bdrv_get_info = vpc_get_info, .bdrv_get_info = vpc_get_info,

View File

@ -1179,6 +1179,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
bs->read_only = 0; bs->read_only = 0;
} }
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
bs->total_sectors = cyls * heads * secs; bs->total_sectors = cyls * heads * secs;
if (init_directories(s, dirname, heads, secs, errp)) { if (init_directories(s, dirname, heads, secs, errp)) {
@ -1421,14 +1422,31 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
return 0; return 0;
} }
static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
uint8_t *buf, int nb_sectors) vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
int ret; int ret;
BDRVVVFATState *s = bs->opaque; BDRVVVFATState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
void *buf;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
buf = g_try_malloc(bytes);
if (bytes && buf == NULL) {
return -ENOMEM;
}
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
ret = vvfat_read(bs, sector_num, buf, nb_sectors); ret = vvfat_read(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
qemu_iovec_from_buf(qiov, 0, buf, bytes);
g_free(buf);
return ret; return ret;
} }
@ -2880,14 +2898,31 @@ DLOG(checkpoint());
return 0; return 0;
} }
static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
const uint8_t *buf, int nb_sectors) vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
int ret; int ret;
BDRVVVFATState *s = bs->opaque; BDRVVVFATState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS;
int nb_sectors = bytes >> BDRV_SECTOR_BITS;
void *buf;
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
buf = g_try_malloc(bytes);
if (bytes && buf == NULL) {
return -ENOMEM;
}
qemu_iovec_to_buf(qiov, 0, buf, bytes);
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
ret = vvfat_write(bs, sector_num, buf, nb_sectors); ret = vvfat_write(bs, sector_num, buf, nb_sectors);
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
g_free(buf);
return ret; return ret;
} }
@ -2904,8 +2939,10 @@ static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
return BDRV_BLOCK_DATA; return BDRV_BLOCK_DATA;
} }
static int write_target_commit(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn
const uint8_t* buffer, int nb_sectors) { write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
return try_commit(s); return try_commit(s);
} }
@ -2918,7 +2955,7 @@ static void write_target_close(BlockDriverState *bs) {
static BlockDriver vvfat_write_target = { static BlockDriver vvfat_write_target = {
.format_name = "vvfat_write_target", .format_name = "vvfat_write_target",
.bdrv_write = write_target_commit, .bdrv_co_pwritev = write_target_commit,
.bdrv_close = write_target_close, .bdrv_close = write_target_close,
}; };
@ -3014,8 +3051,8 @@ static BlockDriver bdrv_vvfat = {
.bdrv_file_open = vvfat_open, .bdrv_file_open = vvfat_open,
.bdrv_close = vvfat_close, .bdrv_close = vvfat_close,
.bdrv_read = vvfat_co_read, .bdrv_co_preadv = vvfat_co_preadv,
.bdrv_write = vvfat_co_write, .bdrv_co_pwritev = vvfat_co_pwritev,
.bdrv_co_get_block_status = vvfat_co_get_block_status, .bdrv_co_get_block_status = vvfat_co_get_block_status,
}; };

View File

@ -73,7 +73,7 @@ static int if_max_devs[IF_COUNT] = {
* Do not change these numbers! They govern how drive option * Do not change these numbers! They govern how drive option
* index maps to unit and bus. That mapping is ABI. * index maps to unit and bus. That mapping is ABI.
* *
* All controllers used to imlement if=T drives need to support * All controllers used to implement if=T drives need to support
* if_max_devs[T] units, for any T with if_max_devs[T] != 0. * if_max_devs[T] units, for any T with if_max_devs[T] != 0.
* Otherwise, some index values map to "impossible" bus, unit * Otherwise, some index values map to "impossible" bus, unit
* values. * values.
@ -4092,6 +4092,61 @@ out:
aio_context_release(aio_context); aio_context_release(aio_context);
} }
static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
const char *child_name)
{
BdrvChild *child;
QLIST_FOREACH(child, &parent_bs->children, next) {
if (strcmp(child->name, child_name) == 0) {
return child;
}
}
return NULL;
}
void qmp_x_blockdev_change(const char *parent, bool has_child,
const char *child, bool has_node,
const char *node, Error **errp)
{
BlockDriverState *parent_bs, *new_bs = NULL;
BdrvChild *p_child;
parent_bs = bdrv_lookup_bs(parent, parent, errp);
if (!parent_bs) {
return;
}
if (has_child == has_node) {
if (has_child) {
error_setg(errp, "The parameters child and node are in conflict");
} else {
error_setg(errp, "Either child or node must be specified");
}
return;
}
if (has_child) {
p_child = bdrv_find_child(parent_bs, child);
if (!p_child) {
error_setg(errp, "Node '%s' does not have child '%s'",
parent, child);
return;
}
bdrv_del_child(parent_bs, p_child, errp);
}
if (has_node) {
new_bs = bdrv_find_node(node);
if (!new_bs) {
error_setg(errp, "Node '%s' not found", node);
return;
}
bdrv_add_child(parent_bs, new_bs, errp);
}
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp) BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{ {
BlockJobInfoList *head = NULL, **p_next = &head; BlockJobInfoList *head = NULL, **p_next = &head;

View File

@ -73,7 +73,7 @@ typedef struct {
BlockBackend *blk; BlockBackend *blk;
BlockAIOCB *acb; BlockAIOCB *acb;
QEMUSGList *sg; QEMUSGList *sg;
uint64_t sector_num; uint64_t offset;
DMADirection dir; DMADirection dir;
int sg_cur_index; int sg_cur_index;
dma_addr_t sg_cur_byte; dma_addr_t sg_cur_byte;
@ -130,7 +130,7 @@ static void dma_blk_cb(void *opaque, int ret)
trace_dma_blk_cb(dbs, ret); trace_dma_blk_cb(dbs, ret);
dbs->acb = NULL; dbs->acb = NULL;
dbs->sector_num += dbs->iov.size / 512; dbs->offset += dbs->iov.size;
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
dma_complete(dbs, ret); dma_complete(dbs, ret);
@ -164,8 +164,8 @@ static void dma_blk_cb(void *opaque, int ret)
qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK); qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK);
} }
dbs->acb = dbs->io_func(dbs->blk, dbs->sector_num, &dbs->iov, dbs->acb = dbs->io_func(dbs->blk, dbs->offset, &dbs->iov, 0,
dbs->iov.size / 512, dma_blk_cb, dbs); dma_blk_cb, dbs);
assert(dbs->acb); assert(dbs->acb);
} }
@ -203,7 +203,7 @@ BlockAIOCB *dma_blk_io(
dbs->acb = NULL; dbs->acb = NULL;
dbs->blk = blk; dbs->blk = blk;
dbs->sg = sg; dbs->sg = sg;
dbs->sector_num = sector_num; dbs->offset = sector_num << BDRV_SECTOR_BITS;
dbs->sg_cur_index = 0; dbs->sg_cur_index = 0;
dbs->sg_cur_byte = 0; dbs->sg_cur_byte = 0;
dbs->dir = dir; dbs->dir = dir;
@ -219,7 +219,7 @@ BlockAIOCB *dma_blk_read(BlockBackend *blk,
QEMUSGList *sg, uint64_t sector, QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque) void (*cb)(void *opaque, int ret), void *opaque)
{ {
return dma_blk_io(blk, sg, sector, blk_aio_readv, cb, opaque, return dma_blk_io(blk, sg, sector, blk_aio_preadv, cb, opaque,
DMA_DIRECTION_FROM_DEVICE); DMA_DIRECTION_FROM_DEVICE);
} }
@ -227,7 +227,7 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk,
QEMUSGList *sg, uint64_t sector, QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque) void (*cb)(void *opaque, int ret), void *opaque)
{ {
return dma_blk_io(blk, sg, sector, blk_aio_writev, cb, opaque, return dma_blk_io(blk, sg, sector, blk_aio_pwritev, cb, opaque,
DMA_DIRECTION_TO_DEVICE); DMA_DIRECTION_TO_DEVICE);
} }

View File

@ -223,6 +223,13 @@ static int fd_sector(FDrive *drv)
NUM_SIDES(drv)); NUM_SIDES(drv));
} }
/* Returns current position, in bytes, for given drive */
static int fd_offset(FDrive *drv)
{
g_assert(fd_sector(drv) < INT_MAX >> BDRV_SECTOR_BITS);
return fd_sector(drv) << BDRV_SECTOR_BITS;
}
/* Seek to a new position: /* Seek to a new position:
* returns 0 if already on right track * returns 0 if already on right track
* returns 1 if track changed * returns 1 if track changed
@ -1629,8 +1636,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
if (fdctrl->data_dir != FD_DIR_WRITE || if (fdctrl->data_dir != FD_DIR_WRITE ||
len < FD_SECTOR_LEN || rel_pos != 0) { len < FD_SECTOR_LEN || rel_pos != 0) {
/* READ & SCAN commands and realign to a sector for WRITE */ /* READ & SCAN commands and realign to a sector for WRITE */
if (blk_read(cur_drv->blk, fd_sector(cur_drv), if (blk_pread(cur_drv->blk, fd_offset(cur_drv),
fdctrl->fifo, 1) < 0) { fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) {
FLOPPY_DPRINTF("Floppy: error getting sector %d\n", FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
fd_sector(cur_drv)); fd_sector(cur_drv));
/* Sure, image size is too small... */ /* Sure, image size is too small... */
@ -1657,8 +1664,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos, k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
fdctrl->data_pos, len); fdctrl->data_pos, len);
if (blk_write(cur_drv->blk, fd_sector(cur_drv), if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv),
fdctrl->fifo, 1) < 0) { fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) {
FLOPPY_DPRINTF("error writing sector %d\n", FLOPPY_DPRINTF("error writing sector %d\n",
fd_sector(cur_drv)); fd_sector(cur_drv));
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
@ -1741,7 +1748,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
fd_sector(cur_drv)); fd_sector(cur_drv));
return 0; return 0;
} }
if (blk_read(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) if (blk_pread(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
BDRV_SECTOR_SIZE)
< 0) { < 0) {
FLOPPY_DPRINTF("error getting sector %d\n", FLOPPY_DPRINTF("error getting sector %d\n",
fd_sector(cur_drv)); fd_sector(cur_drv));
@ -1820,7 +1828,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
} }
memset(fdctrl->fifo, 0, FD_SECTOR_LEN); memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
if (cur_drv->blk == NULL || if (cur_drv->blk == NULL ||
blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
BDRV_SECTOR_SIZE, 0) < 0) {
FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv)); FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
} else { } else {
@ -2243,8 +2252,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
if (pos == FD_SECTOR_LEN - 1 || if (pos == FD_SECTOR_LEN - 1 ||
fdctrl->data_pos == fdctrl->data_len) { fdctrl->data_pos == fdctrl->data_len) {
cur_drv = get_cur_drv(fdctrl); cur_drv = get_cur_drv(fdctrl);
if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
< 0) { BDRV_SECTOR_SIZE, 0) < 0) {
FLOPPY_DPRINTF("error writing sector %d\n", FLOPPY_DPRINTF("error writing sector %d\n",
fd_sector(cur_drv)); fd_sector(cur_drv));
break; break;

View File

@ -66,7 +66,7 @@ static int guess_disk_lchs(BlockBackend *blk,
* but also in async I/O mode. So the I/O throttling function has to * but also in async I/O mode. So the I/O throttling function has to
* be disabled temporarily here, not permanently. * be disabled temporarily here, not permanently.
*/ */
if (blk_read_unthrottled(blk, 0, buf, 1) < 0) { if (blk_pread_unthrottled(blk, 0, buf, BDRV_SECTOR_SIZE) < 0) {
return -1; return -1;
} }
/* test msdos magic */ /* test msdos magic */

View File

@ -358,25 +358,21 @@ static void blk_sync_complete(void *opaque, int ret)
static void flash_sync_page(Flash *s, int page) static void flash_sync_page(Flash *s, int page)
{ {
int blk_sector, nb_sectors;
QEMUIOVector iov; QEMUIOVector iov;
if (!s->blk || blk_is_read_only(s->blk)) { if (!s->blk || blk_is_read_only(s->blk)) {
return; return;
} }
blk_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
qemu_iovec_init(&iov, 1); qemu_iovec_init(&iov, 1);
qemu_iovec_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE, qemu_iovec_add(&iov, s->storage + page * s->pi->page_size,
nb_sectors * BDRV_SECTOR_SIZE); s->pi->page_size);
blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete, blk_aio_pwritev(s->blk, page * s->pi->page_size, &iov, 0,
NULL); blk_sync_complete, NULL);
} }
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
{ {
int64_t start, end, nb_sectors;
QEMUIOVector iov; QEMUIOVector iov;
if (!s->blk || blk_is_read_only(s->blk)) { if (!s->blk || blk_is_read_only(s->blk)) {
@ -384,13 +380,9 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
} }
assert(!(len % BDRV_SECTOR_SIZE)); assert(!(len % BDRV_SECTOR_SIZE));
start = off / BDRV_SECTOR_SIZE;
end = (off + len) / BDRV_SECTOR_SIZE;
nb_sectors = end - start;
qemu_iovec_init(&iov, 1); qemu_iovec_init(&iov, 1);
qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), qemu_iovec_add(&iov, s->storage + off, len);
nb_sectors * BDRV_SECTOR_SIZE); blk_aio_pwritev(s->blk, off, &iov, 0, blk_sync_complete, NULL);
blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL);
} }
static void flash_erase(Flash *s, int offset, FlashCMD cmd) static void flash_erase(Flash *s, int offset, FlashCMD cmd)
@ -907,8 +899,7 @@ static int m25p80_init(SSISlave *ss)
s->storage = blk_blockalign(s->blk, s->size); s->storage = blk_blockalign(s->blk, s->size);
/* FIXME: Move to late init */ /* FIXME: Move to late init */
if (blk_read(s->blk, 0, s->storage, if (blk_pread(s->blk, 0, s->storage, s->size)) {
DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) {
fprintf(stderr, "Failed to initialize SPI flash!\n"); fprintf(stderr, "Failed to initialize SPI flash!\n");
return 1; return 1;
} }

View File

@ -663,7 +663,8 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
sector = SECTOR(s->addr); sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset; off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr); soff = SECTOR_OFFSET(s->addr);
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS) < 0) { if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return; return;
} }
@ -675,21 +676,24 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE)); MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
} }
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS) < 0) { if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
} }
} else { } else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9; sector = off >> 9;
soff = off & 0x1ff; soff = off & 0x1ff;
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) { if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return; return;
} }
mem_and(iobuf + soff, s->io, s->iolen); mem_and(iobuf + soff, s->io, s->iolen);
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) { if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
} }
} }
@ -716,17 +720,20 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
i = SECTOR(addr); i = SECTOR(addr);
page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift))); page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
for (; i < page; i ++) for (; i < page; i ++)
if (blk_write(s->blk, i, iobuf, 1) < 0) { if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, iobuf,
BDRV_SECTOR_SIZE, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, i); printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
} }
} else { } else {
addr = PAGE_START(addr); addr = PAGE_START(addr);
page = addr >> 9; page = addr >> 9;
if (blk_read(s->blk, page, iobuf, 1) < 0) { if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
BDRV_SECTOR_SIZE) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page); printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
} }
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (blk_write(s->blk, page, iobuf, 1) < 0) { if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
BDRV_SECTOR_SIZE, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page); printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
} }
@ -734,18 +741,20 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
i = (addr & ~0x1ff) + 0x200; i = (addr & ~0x1ff) + 0x200;
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200) { i < addr; i += 0x200) {
if (blk_write(s->blk, i >> 9, iobuf, 1) < 0) { if (blk_pwrite(s->blk, i, iobuf, BDRV_SECTOR_SIZE, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", printf("%s: write error in sector %" PRIu64 "\n",
__func__, i >> 9); __func__, i >> 9);
} }
} }
page = i >> 9; page = i >> 9;
if (blk_read(s->blk, page, iobuf, 1) < 0) { if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
BDRV_SECTOR_SIZE) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page); printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
} }
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (blk_write(s->blk, page, iobuf, 1) < 0) { if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
BDRV_SECTOR_SIZE, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page); printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
} }
} }
@ -760,7 +769,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
if (s->blk) { if (s->blk) {
if (s->mem_oob) { if (s->mem_oob) {
if (blk_read(s->blk, SECTOR(addr), s->io, PAGE_SECTORS) < 0) { if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, s->io,
PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", printf("%s: read error in sector %" PRIu64 "\n",
__func__, SECTOR(addr)); __func__, SECTOR(addr));
} }
@ -769,8 +779,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
OOB_SIZE); OOB_SIZE);
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
} else { } else {
if (blk_read(s->blk, PAGE_START(addr) >> 9, if (blk_pread(s->blk, PAGE_START(addr), s->io,
s->io, (PAGE_SECTORS + 2)) < 0) { (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", printf("%s: read error in sector %" PRIu64 "\n",
__func__, PAGE_START(addr) >> 9); __func__, PAGE_START(addr) >> 9);
} }

View File

@ -224,7 +224,8 @@ static void onenand_reset(OneNANDState *s, int cold)
/* Lock the whole flash */ /* Lock the whole flash */
memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks); memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
if (s->blk_cur && blk_read(s->blk_cur, 0, s->boot[0], 8) < 0) { if (s->blk_cur && blk_pread(s->blk_cur, 0, s->boot[0],
8 << BDRV_SECTOR_BITS) < 0) {
hw_error("%s: Loading the BootRAM failed.\n", __func__); hw_error("%s: Loading the BootRAM failed.\n", __func__);
} }
} }
@ -240,8 +241,11 @@ static void onenand_system_reset(DeviceState *dev)
static inline int onenand_load_main(OneNANDState *s, int sec, int secn, static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
void *dest) void *dest)
{ {
assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
if (s->blk_cur) { if (s->blk_cur) {
return blk_read(s->blk_cur, sec, dest, secn) < 0; return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS, dest,
secn << BDRV_SECTOR_BITS) < 0;
} else if (sec + secn > s->secs_cur) { } else if (sec + secn > s->secs_cur) {
return 1; return 1;
} }
@ -257,19 +261,22 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
int result = 0; int result = 0;
if (secn > 0) { if (secn > 0) {
uint32_t size = (uint32_t)secn * 512; uint32_t size = secn << BDRV_SECTOR_BITS;
uint32_t offset = sec << BDRV_SECTOR_BITS;
assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
const uint8_t *sp = (const uint8_t *)src; const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0; uint8_t *dp = 0;
if (s->blk_cur) { if (s->blk_cur) {
dp = g_malloc(size); dp = g_malloc(size);
if (!dp || blk_read(s->blk_cur, sec, dp, secn) < 0) { if (!dp || blk_pread(s->blk_cur, offset, dp, size) < 0) {
result = 1; result = 1;
} }
} else { } else {
if (sec + secn > s->secs_cur) { if (sec + secn > s->secs_cur) {
result = 1; result = 1;
} else { } else {
dp = (uint8_t *)s->current + (sec << 9); dp = (uint8_t *)s->current + offset;
} }
} }
if (!result) { if (!result) {
@ -278,7 +285,7 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
dp[i] &= sp[i]; dp[i] &= sp[i];
} }
if (s->blk_cur) { if (s->blk_cur) {
result = blk_write(s->blk_cur, sec, dp, secn) < 0; result = blk_pwrite(s->blk_cur, offset, dp, size, 0) < 0;
} }
} }
if (dp && s->blk_cur) { if (dp && s->blk_cur) {
@ -295,7 +302,8 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
uint8_t buf[512]; uint8_t buf[512];
if (s->blk_cur) { if (s->blk_cur) {
if (blk_read(s->blk_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) { uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
if (blk_pread(s->blk_cur, offset, buf, BDRV_SECTOR_SIZE) < 0) {
return 1; return 1;
} }
memcpy(dest, buf + ((sec & 31) << 4), secn << 4); memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
@ -304,7 +312,7 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
} else { } else {
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4); memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
} }
return 0; return 0;
} }
@ -315,10 +323,12 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
if (secn > 0) { if (secn > 0) {
const uint8_t *sp = (const uint8_t *)src; const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0, *dpp = 0; uint8_t *dp = 0, *dpp = 0;
uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5));
if (s->blk_cur) { if (s->blk_cur) {
dp = g_malloc(512); dp = g_malloc(512);
if (!dp if (!dp
|| blk_read(s->blk_cur, s->secs_cur + (sec >> 5), dp, 1) < 0) { || blk_pread(s->blk_cur, offset, dp, BDRV_SECTOR_SIZE) < 0) {
result = 1; result = 1;
} else { } else {
dpp = dp + ((sec & 31) << 4); dpp = dp + ((sec & 31) << 4);
@ -336,8 +346,8 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
dpp[i] &= sp[i]; dpp[i] &= sp[i];
} }
if (s->blk_cur) { if (s->blk_cur) {
result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5), result = blk_pwrite(s->blk_cur, offset, dp,
dp, 1) < 0; BDRV_SECTOR_SIZE, 0) < 0;
} }
} }
g_free(dp); g_free(dp);
@ -355,14 +365,17 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num)
for (; num > 0; num--, sec++) { for (; num > 0; num--, sec++) {
if (s->blk_cur) { if (s->blk_cur) {
int erasesec = s->secs_cur + (sec >> 5); int erasesec = s->secs_cur + (sec >> 5);
if (blk_write(s->blk_cur, sec, blankbuf, 1) < 0) { if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS, blankbuf,
BDRV_SECTOR_SIZE, 0) < 0) {
goto fail; goto fail;
} }
if (blk_read(s->blk_cur, erasesec, tmpbuf, 1) < 0) { if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf,
BDRV_SECTOR_SIZE) < 0) {
goto fail; goto fail;
} }
memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4); memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
if (blk_write(s->blk_cur, erasesec, tmpbuf, 1) < 0) { if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf,
BDRV_SECTOR_SIZE, 0) < 0) {
goto fail; goto fail;
} }
} else { } else {

View File

@ -413,11 +413,11 @@ static void pflash_update(pflash_t *pfl, int offset,
int offset_end; int offset_end;
if (pfl->blk) { if (pfl->blk) {
offset_end = offset + size; offset_end = offset + size;
/* round to sectors */ /* widen to sector boundaries */
offset = offset >> 9; offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
offset_end = (offset_end + 511) >> 9; offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
blk_write(pfl->blk, offset, pfl->storage + (offset << 9), blk_pwrite(pfl->blk, offset, pfl->storage + offset,
offset_end - offset); offset_end - offset, 0);
} }
} }
@ -739,7 +739,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
if (pfl->blk) { if (pfl->blk) {
/* read the initial flash content */ /* read the initial flash content */
ret = blk_read(pfl->blk, 0, pfl->storage, total_len >> 9); ret = blk_pread(pfl->blk, 0, pfl->storage, total_len);
if (ret < 0) { if (ret < 0) {
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl)); vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));

View File

@ -253,11 +253,11 @@ static void pflash_update(pflash_t *pfl, int offset,
int offset_end; int offset_end;
if (pfl->blk) { if (pfl->blk) {
offset_end = offset + size; offset_end = offset + size;
/* round to sectors */ /* widen to sector boundaries */
offset = offset >> 9; offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
offset_end = (offset_end + 511) >> 9; offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
blk_write(pfl->blk, offset, pfl->storage + (offset << 9), blk_pwrite(pfl->blk, offset, pfl->storage + offset,
offset_end - offset); offset_end - offset, 0);
} }
} }
@ -622,7 +622,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
pfl->chip_len = chip_len; pfl->chip_len = chip_len;
if (pfl->blk) { if (pfl->blk) {
/* read the initial flash content */ /* read the initial flash content */
ret = blk_read(pfl->blk, 0, pfl->storage, chip_len >> 9); ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len);
if (ret < 0) { if (ret < 0) {
vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl)); vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
error_setg(errp, "failed to read the initial flash content"); error_setg(errp, "failed to read the initial flash content");

View File

@ -322,7 +322,6 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
{ {
QEMUIOVector *qiov = &mrb->reqs[start]->qiov; QEMUIOVector *qiov = &mrb->reqs[start]->qiov;
int64_t sector_num = mrb->reqs[start]->sector_num; int64_t sector_num = mrb->reqs[start]->sector_num;
int nb_sectors = mrb->reqs[start]->qiov.size / BDRV_SECTOR_SIZE;
bool is_write = mrb->is_write; bool is_write = mrb->is_write;
if (num_reqs > 1) { if (num_reqs > 1) {
@ -331,7 +330,7 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
int tmp_niov = qiov->niov; int tmp_niov = qiov->niov;
/* mrb->reqs[start]->qiov was initialized from external so we can't /* mrb->reqs[start]->qiov was initialized from external so we can't
* modifiy it here. We need to initialize it locally and then add the * modify it here. We need to initialize it locally and then add the
* external iovecs. */ * external iovecs. */
qemu_iovec_init(qiov, niov); qemu_iovec_init(qiov, niov);
@ -343,23 +342,22 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
qemu_iovec_concat(qiov, &mrb->reqs[i]->qiov, 0, qemu_iovec_concat(qiov, &mrb->reqs[i]->qiov, 0,
mrb->reqs[i]->qiov.size); mrb->reqs[i]->qiov.size);
mrb->reqs[i - 1]->mr_next = mrb->reqs[i]; mrb->reqs[i - 1]->mr_next = mrb->reqs[i];
nb_sectors += mrb->reqs[i]->qiov.size / BDRV_SECTOR_SIZE;
} }
assert(nb_sectors == qiov->size / BDRV_SECTOR_SIZE);
trace_virtio_blk_submit_multireq(mrb, start, num_reqs, sector_num, trace_virtio_blk_submit_multireq(mrb, start, num_reqs,
nb_sectors, is_write); sector_num << BDRV_SECTOR_BITS,
qiov->size, is_write);
block_acct_merge_done(blk_get_stats(blk), block_acct_merge_done(blk_get_stats(blk),
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ, is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ,
num_reqs - 1); num_reqs - 1);
} }
if (is_write) { if (is_write) {
blk_aio_writev(blk, sector_num, qiov, nb_sectors, blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0,
virtio_blk_rw_complete, mrb->reqs[start]); virtio_blk_rw_complete, mrb->reqs[start]);
} else { } else {
blk_aio_readv(blk, sector_num, qiov, nb_sectors, blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0,
virtio_blk_rw_complete, mrb->reqs[start]); virtio_blk_rw_complete, mrb->reqs[start]);
} }
} }

View File

@ -554,9 +554,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
ioreq->v.size, BLOCK_ACCT_READ); ioreq->v.size, BLOCK_ACCT_READ);
ioreq->aio_inflight++; ioreq->aio_inflight++;
blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE, blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0,
&ioreq->v, ioreq->v.size / BLOCK_SIZE, qemu_aio_complete, ioreq);
qemu_aio_complete, ioreq);
break; break;
case BLKIF_OP_WRITE: case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_FLUSH_DISKCACHE:
@ -569,9 +568,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
ioreq->req.operation == BLKIF_OP_WRITE ? ioreq->req.operation == BLKIF_OP_WRITE ?
BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
ioreq->aio_inflight++; ioreq->aio_inflight++;
blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE, blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0,
&ioreq->v, ioreq->v.size / BLOCK_SIZE, qemu_aio_complete, ioreq);
qemu_aio_complete, ioreq);
break; break;
case BLKIF_OP_DISCARD: case BLKIF_OP_DISCARD:
{ {

View File

@ -28,6 +28,9 @@
#include "hw/scsi/scsi.h" #include "hw/scsi/scsi.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#define ATAPI_SECTOR_BITS (2 + BDRV_SECTOR_BITS)
#define ATAPI_SECTOR_SIZE (1 << ATAPI_SECTOR_BITS)
static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
static void padstr8(uint8_t *buf, int buf_size, const char *src) static void padstr8(uint8_t *buf, int buf_size, const char *src)
@ -111,7 +114,7 @@ cd_read_sector_sync(IDEState *s)
{ {
int ret; int ret;
block_acct_start(blk_get_stats(s->blk), &s->acct, block_acct_start(blk_get_stats(s->blk), &s->acct,
4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ);
#ifdef DEBUG_IDE_ATAPI #ifdef DEBUG_IDE_ATAPI
printf("cd_read_sector_sync: lba=%d\n", s->lba); printf("cd_read_sector_sync: lba=%d\n", s->lba);
@ -119,12 +122,12 @@ cd_read_sector_sync(IDEState *s)
switch (s->cd_sector_size) { switch (s->cd_sector_size) {
case 2048: case 2048:
ret = blk_read(s->blk, (int64_t)s->lba << 2, ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS,
s->io_buffer, 4); s->io_buffer, ATAPI_SECTOR_SIZE);
break; break;
case 2352: case 2352:
ret = blk_read(s->blk, (int64_t)s->lba << 2, ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS,
s->io_buffer + 16, 4); s->io_buffer + 16, ATAPI_SECTOR_SIZE);
if (ret >= 0) { if (ret >= 0) {
cd_data_to_raw(s->io_buffer, s->lba); cd_data_to_raw(s->io_buffer, s->lba);
} }
@ -182,7 +185,7 @@ static int cd_read_sector(IDEState *s)
s->iov.iov_base = (s->cd_sector_size == 2352) ? s->iov.iov_base = (s->cd_sector_size == 2352) ?
s->io_buffer + 16 : s->io_buffer; s->io_buffer + 16 : s->io_buffer;
s->iov.iov_len = 4 * BDRV_SECTOR_SIZE; s->iov.iov_len = ATAPI_SECTOR_SIZE;
qemu_iovec_init_external(&s->qiov, &s->iov, 1); qemu_iovec_init_external(&s->qiov, &s->iov, 1);
#ifdef DEBUG_IDE_ATAPI #ifdef DEBUG_IDE_ATAPI
@ -190,7 +193,7 @@ static int cd_read_sector(IDEState *s)
#endif #endif
block_acct_start(blk_get_stats(s->blk), &s->acct, block_acct_start(blk_get_stats(s->blk), &s->acct,
4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ);
ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, 4, ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, 4,
cd_read_sector_cb, s); cd_read_sector_cb, s);
@ -435,7 +438,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
#endif #endif
s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
s->bus->dma->iov.iov_len = n * 4 * 512; s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE;
qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2, s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2,

View File

@ -442,7 +442,7 @@ static void ide_issue_trim_cb(void *opaque, int ret)
} }
BlockAIOCB *ide_issue_trim(BlockBackend *blk, BlockAIOCB *ide_issue_trim(BlockBackend *blk,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, int64_t offset, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
TrimAIOCB *iocb; TrimAIOCB *iocb;
@ -616,8 +616,8 @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
req->iov.iov_len = iov->size; req->iov.iov_len = iov->size;
qemu_iovec_init_external(&req->qiov, &req->iov, 1); qemu_iovec_init_external(&req->qiov, &req->iov, 1);
aioreq = blk_aio_readv(s->blk, sector_num, &req->qiov, nb_sectors, aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS,
ide_buffered_readv_cb, req); &req->qiov, 0, ide_buffered_readv_cb, req);
QLIST_INSERT_HEAD(&s->buffered_requests, req, list); QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
return aioreq; return aioreq;
@ -1006,8 +1006,8 @@ static void ide_sector_write(IDEState *s)
block_acct_start(blk_get_stats(s->blk), &s->acct, block_acct_start(blk_get_stats(s->blk), &s->acct,
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE); n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n, s->pio_aiocb = blk_aio_pwritev(s->blk, sector_num << BDRV_SECTOR_BITS,
ide_sector_write_cb, s); &s->qiov, 0, ide_sector_write_cb, s);
} }
static void ide_flush_cb(void *opaque, int ret) static void ide_flush_cb(void *opaque, int ret)

View File

@ -614,7 +614,7 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
void ide_transfer_stop(IDEState *s); void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s, bool more); void ide_set_inactive(IDEState *s, bool more);
BlockAIOCB *ide_issue_trim(BlockBackend *blk, BlockAIOCB *ide_issue_trim(BlockBackend *blk,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, int64_t offset, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num, BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *iov, int nb_sectors,

View File

@ -55,8 +55,8 @@ static const int debug_macio = 0;
/* /*
* Unaligned DMA read/write access functions required for OS X/Darwin which * Unaligned DMA read/write access functions required for OS X/Darwin which
* don't perform DMA transactions on sector boundaries. These functions are * don't perform DMA transactions on sector boundaries. These functions are
* modelled on bdrv_co_do_preadv()/bdrv_co_do_pwritev() and so should be * modelled on bdrv_co_preadv()/bdrv_co_pwritev() and so should be easy to
* easy to remove if the unaligned block APIs are ever exposed. * remove if the unaligned block APIs are ever exposed.
*/ */
static void pmac_dma_read(BlockBackend *blk, static void pmac_dma_read(BlockBackend *blk,
@ -120,8 +120,7 @@ static void pmac_dma_read(BlockBackend *blk,
MACIO_DPRINTF("--- Block read transfer - sector_num: %" PRIx64 " " MACIO_DPRINTF("--- Block read transfer - sector_num: %" PRIx64 " "
"nsector: %x\n", (offset >> 9), (bytes >> 9)); "nsector: %x\n", (offset >> 9), (bytes >> 9));
s->bus->dma->aiocb = blk_aio_readv(blk, (offset >> 9), &io->iov, s->bus->dma->aiocb = blk_aio_preadv(blk, offset, &io->iov, 0, cb, io);
(bytes >> 9), cb, io);
} }
static void pmac_dma_write(BlockBackend *blk, static void pmac_dma_write(BlockBackend *blk,
@ -205,8 +204,7 @@ static void pmac_dma_write(BlockBackend *blk,
MACIO_DPRINTF("--- Block write transfer - sector_num: %" PRIx64 " " MACIO_DPRINTF("--- Block write transfer - sector_num: %" PRIx64 " "
"nsector: %x\n", (offset >> 9), (bytes >> 9)); "nsector: %x\n", (offset >> 9), (bytes >> 9));
s->bus->dma->aiocb = blk_aio_writev(blk, (offset >> 9), &io->iov, s->bus->dma->aiocb = blk_aio_pwritev(blk, offset, &io->iov, 0, cb, io);
(bytes >> 9), cb, io);
} }
static void pmac_dma_trim(BlockBackend *blk, static void pmac_dma_trim(BlockBackend *blk,
@ -232,8 +230,7 @@ static void pmac_dma_trim(BlockBackend *blk,
s->io_buffer_index += io->len; s->io_buffer_index += io->len;
io->len = 0; io->len = 0;
s->bus->dma->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov, s->bus->dma->aiocb = ide_issue_trim(blk, offset, &io->iov, 0, cb, io);
(bytes >> 9), cb, io);
} }
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)

View File

@ -124,7 +124,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
alen = len; alen = len;
if (nvram->blk) { if (nvram->blk) {
alen = blk_pwrite(nvram->blk, offset, membuf, len); alen = blk_pwrite(nvram->blk, offset, membuf, len, 0);
} }
assert(nvram->buf); assert(nvram->buf);
@ -190,7 +190,7 @@ static int spapr_nvram_post_load(void *opaque, int version_id)
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque); sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
if (nvram->blk) { if (nvram->blk) {
int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size); int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size, 0);
if (alen < 0) { if (alen < 0) {
return alen; return alen;

View File

@ -108,7 +108,7 @@ static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
scsi_req_complete(&r->req, CHECK_CONDITION); scsi_req_complete(&r->req, CHECK_CONDITION);
} }
static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) static void scsi_init_iovec(SCSIDiskReq *r, size_t size)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@ -118,7 +118,6 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
} }
r->iov.iov_len = MIN(r->sector_count * 512, r->buflen); r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
qemu_iovec_init_external(&r->qiov, &r->iov, 1); qemu_iovec_init_external(&r->qiov, &r->iov, 1);
return r->qiov.size / 512;
} }
static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
@ -316,7 +315,6 @@ done:
static void scsi_do_read(SCSIDiskReq *r, int ret) static void scsi_do_read(SCSIDiskReq *r, int ret)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
assert (r->req.aiocb == NULL); assert (r->req.aiocb == NULL);
@ -340,11 +338,12 @@ static void scsi_do_read(SCSIDiskReq *r, int ret)
r->req.aiocb = dma_blk_read(s->qdev.conf.blk, r->req.sg, r->sector, r->req.aiocb = dma_blk_read(s->qdev.conf.blk, r->req.sg, r->sector,
scsi_dma_complete, r); scsi_dma_complete, r);
} else { } else {
n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); r->qiov.size, BLOCK_ACCT_READ);
r->req.aiocb = blk_aio_readv(s->qdev.conf.blk, r->sector, &r->qiov, n, r->req.aiocb = blk_aio_preadv(s->qdev.conf.blk,
scsi_read_complete, r); r->sector << BDRV_SECTOR_BITS, &r->qiov,
0, scsi_read_complete, r);
} }
done: done:
@ -504,7 +503,6 @@ static void scsi_write_data(SCSIRequest *req)
{ {
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
/* No data transfer may already be in progress */ /* No data transfer may already be in progress */
assert(r->req.aiocb == NULL); assert(r->req.aiocb == NULL);
@ -544,11 +542,11 @@ static void scsi_write_data(SCSIRequest *req)
r->req.aiocb = dma_blk_write(s->qdev.conf.blk, r->req.sg, r->sector, r->req.aiocb = dma_blk_write(s->qdev.conf.blk, r->req.sg, r->sector,
scsi_dma_complete, r); scsi_dma_complete, r);
} else { } else {
n = r->qiov.size / 512;
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE); r->qiov.size, BLOCK_ACCT_WRITE);
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, r->sector, &r->qiov, n, r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
scsi_write_complete, r); r->sector << BDRV_SECTOR_BITS, &r->qiov,
0, scsi_write_complete, r);
} }
} }
@ -1730,13 +1728,13 @@ static void scsi_write_same_complete(void *opaque, int ret)
if (data->iov.iov_len) { if (data->iov.iov_len) {
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
data->iov.iov_len, BLOCK_ACCT_WRITE); data->iov.iov_len, BLOCK_ACCT_WRITE);
/* blk_aio_write doesn't like the qiov size being different from /* Reinitialize qiov, to handle unaligned WRITE SAME request
* nb_sectors, make sure they match. * where final qiov may need smaller size */
*/
qemu_iovec_init_external(&data->qiov, &data->iov, 1); qemu_iovec_init_external(&data->qiov, &data->iov, 1);
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector, r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
&data->qiov, data->iov.iov_len / 512, data->sector << BDRV_SECTOR_BITS,
scsi_write_same_complete, data); &data->qiov, 0,
scsi_write_same_complete, data);
return; return;
} }
@ -1781,8 +1779,8 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
nb_sectors * s->qdev.blocksize, nb_sectors * s->qdev.blocksize,
BLOCK_ACCT_WRITE); BLOCK_ACCT_WRITE);
r->req.aiocb = blk_aio_write_zeroes(s->qdev.conf.blk, r->req.aiocb = blk_aio_write_zeroes(s->qdev.conf.blk,
r->req.cmd.lba * (s->qdev.blocksize / 512), r->req.cmd.lba * s->qdev.blocksize,
nb_sectors * (s->qdev.blocksize / 512), nb_sectors * s->qdev.blocksize,
flags, scsi_aio_complete, r); flags, scsi_aio_complete, r);
return; return;
} }
@ -1803,9 +1801,10 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
scsi_req_ref(&r->req); scsi_req_ref(&r->req);
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
data->iov.iov_len, BLOCK_ACCT_WRITE); data->iov.iov_len, BLOCK_ACCT_WRITE);
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector, r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
&data->qiov, data->iov.iov_len / 512, data->sector << BDRV_SECTOR_BITS,
scsi_write_same_complete, data); &data->qiov, 0,
scsi_write_same_complete, data);
} }
static void scsi_disk_emulate_write_data(SCSIRequest *req) static void scsi_disk_emulate_write_data(SCSIRequest *req)

View File

@ -123,7 +123,6 @@ struct SDState {
qemu_irq readonly_cb; qemu_irq readonly_cb;
qemu_irq inserted_cb; qemu_irq inserted_cb;
BlockBackend *blk; BlockBackend *blk;
uint8_t *buf;
bool enable; bool enable;
}; };
@ -551,7 +550,7 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT64(data_start, SDState), VMSTATE_UINT64(data_start, SDState),
VMSTATE_UINT32(data_offset, SDState), VMSTATE_UINT32(data_offset, SDState),
VMSTATE_UINT8_ARRAY(data, SDState, 512), VMSTATE_UINT8_ARRAY(data, SDState, 512),
VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512), VMSTATE_UNUSED_V(1, 512),
VMSTATE_BOOL(enable, SDState), VMSTATE_BOOL(enable, SDState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
@ -1577,57 +1576,17 @@ send_response:
static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
{ {
uint64_t end = addr + len;
DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n", DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
(unsigned long long) addr, len); (unsigned long long) addr, len);
if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) { if (!sd->blk || blk_pread(sd->blk, addr, sd->data, len) < 0) {
fprintf(stderr, "sd_blk_read: read error on host side\n"); fprintf(stderr, "sd_blk_read: read error on host side\n");
return;
} }
if (end > (addr & ~511) + 512) {
memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_read: read error on host side\n");
return;
}
memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
} else
memcpy(sd->data, sd->buf + (addr & 511), len);
} }
static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
{ {
uint64_t end = addr + len; if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 0) {
fprintf(stderr, "sd_blk_write: write error on host side\n");
if ((addr & 511) || len < 512)
if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_write: read error on host side\n");
return;
}
if (end > (addr & ~511) + 512) {
memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
if (blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_write: write error on host side\n");
return;
}
if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_write: read error on host side\n");
return;
}
memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
if (blk_write(sd->blk, end >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_write: write error on host side\n");
}
} else {
memcpy(sd->buf + (addr & 511), sd->data, len);
if (!sd->blk || blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) {
fprintf(stderr, "sd_blk_write: write error on host side\n");
}
} }
} }
@ -1925,8 +1884,6 @@ static void sd_realize(DeviceState *dev, Error **errp)
return; return;
} }
sd->buf = blk_blockalign(sd->blk, 512);
if (sd->blk) { if (sd->blk) {
blk_set_dev_ops(sd->blk, &sd_block_ops, sd); blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
} }

View File

@ -476,6 +476,10 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
void bdrv_ref(BlockDriverState *bs); void bdrv_ref(BlockDriverState *bs);
void bdrv_unref(BlockDriverState *bs); void bdrv_unref(BlockDriverState *bs);
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
const BdrvChildRole *child_role);
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
@ -520,7 +524,8 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
void bdrv_io_plug(BlockDriverState *bs); void bdrv_io_plug(BlockDriverState *bs);
void bdrv_io_unplug(BlockDriverState *bs); void bdrv_io_unplug(BlockDriverState *bs);
void bdrv_flush_io_queue(BlockDriverState *bs); void bdrv_io_unplugged_begin(BlockDriverState *bs);
void bdrv_io_unplugged_end(BlockDriverState *bs);
/** /**
* bdrv_drained_begin: * bdrv_drained_begin:
@ -541,4 +546,8 @@ void bdrv_drained_begin(BlockDriverState *bs);
*/ */
void bdrv_drained_end(BlockDriverState *bs); void bdrv_drained_end(BlockDriverState *bs);
void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
#endif #endif

View File

@ -38,12 +38,12 @@
#include "qemu/throttle.h" #include "qemu/throttle.h"
#define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPAT6 4
#define BLOCK_FLAG_LAZY_REFCOUNTS 8 #define BLOCK_FLAG_LAZY_REFCOUNTS 8
#define BLOCK_OPT_SIZE "size" #define BLOCK_OPT_SIZE "size"
#define BLOCK_OPT_ENCRYPT "encryption" #define BLOCK_OPT_ENCRYPT "encryption"
#define BLOCK_OPT_COMPAT6 "compat6" #define BLOCK_OPT_COMPAT6 "compat6"
#define BLOCK_OPT_HWVERSION "hwversion"
#define BLOCK_OPT_BACKING_FILE "backing_file" #define BLOCK_OPT_BACKING_FILE "backing_file"
#define BLOCK_OPT_BACKING_FMT "backing_fmt" #define BLOCK_OPT_BACKING_FMT "backing_fmt"
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" #define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
@ -127,10 +127,6 @@ struct BlockDriver {
Error **errp); Error **errp);
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags, int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
Error **errp); Error **errp);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs); void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp); int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
@ -153,18 +149,20 @@ struct BlockDriver {
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs, int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags); int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs,
int supported_write_flags; uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
/* /*
* Efficiently zero a region of the disk image. Typically an image format * Efficiently zero a region of the disk image. Typically an image format
* would use a compact metadata representation to implement this. This * would use a compact metadata representation to implement this. This
* function pointer may be NULL and .bdrv_co_writev() will be called * function pointer may be NULL or return -ENOSUP and .bdrv_co_writev()
* instead. * will be called instead.
*/ */
int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs, int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags); int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
@ -294,7 +292,6 @@ struct BlockDriver {
/* io queue for linux-aio */ /* io queue for linux-aio */
void (*bdrv_io_plug)(BlockDriverState *bs); void (*bdrv_io_plug)(BlockDriverState *bs);
void (*bdrv_io_unplug)(BlockDriverState *bs); void (*bdrv_io_unplug)(BlockDriverState *bs);
void (*bdrv_flush_io_queue)(BlockDriverState *bs);
/** /**
* Try to get @bs's logical and physical block size. * Try to get @bs's logical and physical block size.
@ -317,6 +314,11 @@ struct BlockDriver {
*/ */
void (*bdrv_drain)(BlockDriverState *bs); void (*bdrv_drain)(BlockDriverState *bs);
void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
Error **errp);
QLIST_ENTRY(BlockDriver) list; QLIST_ENTRY(BlockDriver) list;
}; };
@ -424,10 +426,10 @@ struct BlockDriverState {
/* I/O throttling. /* I/O throttling.
* throttle_state tells us if this BDS has I/O limits configured. * throttle_state tells us if this BDS has I/O limits configured.
* io_limits_enabled tells us if they are currently being * io_limits_disabled tells us if they are currently being enforced */
* enforced, but it can be temporarily set to false */
CoQueue throttled_reqs[2]; CoQueue throttled_reqs[2];
bool io_limits_enabled; unsigned int io_limits_disabled;
/* The following fields are protected by the ThrottleGroup lock. /* The following fields are protected by the ThrottleGroup lock.
* See the ThrottleGroup documentation for details. */ * See the ThrottleGroup documentation for details. */
ThrottleState *throttle_state; ThrottleState *throttle_state;
@ -446,6 +448,11 @@ struct BlockDriverState {
/* Alignment requirement for offset/length of I/O requests */ /* Alignment requirement for offset/length of I/O requests */
unsigned int request_alignment; unsigned int request_alignment;
/* Flags honored during pwrite (so far: BDRV_REQ_FUA) */
unsigned int supported_write_flags;
/* Flags honored during write_zeroes (so far: BDRV_REQ_FUA,
* BDRV_REQ_MAY_UNMAP) */
unsigned int supported_zero_flags;
/* the following member gives a name to every node on the bs graph. */ /* the following member gives a name to every node on the bs graph. */
char node_name[32]; char node_name[32];
@ -484,6 +491,10 @@ struct BlockDriverState {
uint64_t write_threshold_offset; uint64_t write_threshold_offset;
NotifierWithReturn write_threshold_notifier; NotifierWithReturn write_threshold_notifier;
/* counters for nested bdrv_io_plug and bdrv_io_unplugged_begin */
unsigned io_plugged;
unsigned io_plug_disabled;
int quiesce_counter; int quiesce_counter;
}; };
@ -517,10 +528,10 @@ extern BlockDriver bdrv_qcow2;
*/ */
void bdrv_setup_io_funcs(BlockDriver *bdrv); void bdrv_setup_io_funcs(BlockDriver *bdrv);
int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs, int coroutine_fn bdrv_co_preadv(BlockDriverState *bs,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags); BdrvRequestFlags flags);
int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs, int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags); BdrvRequestFlags flags);
@ -713,6 +724,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
const BdrvChildRole *child_role); const BdrvChildRole *child_role);
void bdrv_root_unref_child(BdrvChild *child); void bdrv_root_unref_child(BdrvChild *child);
void bdrv_no_throttling_begin(BlockDriverState *bs);
void bdrv_no_throttling_end(BlockDriverState *bs);
void blk_dev_change_media_cb(BlockBackend *blk, bool load); void blk_dev_change_media_cb(BlockBackend *blk, bool load);
bool blk_dev_has_removable_media(BlockBackend *blk); bool blk_dev_has_removable_media(BlockBackend *blk);
bool blk_dev_has_tray(BlockBackend *blk); bool blk_dev_has_tray(BlockBackend *blk);

View File

@ -38,6 +38,7 @@ void throttle_group_get_config(BlockDriverState *bs, ThrottleConfig *cfg);
void throttle_group_register_bs(BlockDriverState *bs, const char *groupname); void throttle_group_register_bs(BlockDriverState *bs, const char *groupname);
void throttle_group_unregister_bs(BlockDriverState *bs); void throttle_group_unregister_bs(BlockDriverState *bs);
void throttle_group_restart_bs(BlockDriverState *bs);
void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs, void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs,
unsigned int bytes, unsigned int bytes,

View File

@ -1,7 +1,7 @@
/* /*
* QEMU Block backends * QEMU Block backends
* *
* Copyright (C) 2014 Red Hat, Inc. * Copyright (C) 2014-2016 Red Hat, Inc.
* *
* Authors: * Authors:
* Markus Armbruster <armbru@redhat.com>, * Markus Armbruster <armbru@redhat.com>,
@ -90,28 +90,25 @@ void blk_attach_dev_nofail(BlockBackend *blk, void *dev);
void blk_detach_dev(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev);
void *blk_get_attached_dev(BlockBackend *blk); void *blk_get_attached_dev(BlockBackend *blk);
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque);
int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf, int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
int nb_sectors); int count);
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf, int blk_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors); int count, BdrvRequestFlags flags);
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf, BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors); int count, BdrvRequestFlags flags,
int blk_write_zeroes(BlockBackend *blk, int64_t sector_num,
int nb_sectors, BdrvRequestFlags flags);
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
int nb_sectors, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count); int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count);
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count); int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count,
BdrvRequestFlags flags);
int64_t blk_getlength(BlockBackend *blk); int64_t blk_getlength(BlockBackend *blk);
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr);
int64_t blk_nb_sectors(BlockBackend *blk); int64_t blk_nb_sectors(BlockBackend *blk);
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num, BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_flush(BlockBackend *blk, BlockAIOCB *blk_aio_flush(BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *blk_aio_discard(BlockBackend *blk, BlockAIOCB *blk_aio_discard(BlockBackend *blk,
@ -178,8 +175,8 @@ int blk_get_open_flags_from_root_state(BlockBackend *blk);
void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num, int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset,
int nb_sectors, BdrvRequestFlags flags); int count, BdrvRequestFlags flags);
int blk_write_compressed(BlockBackend *blk, int64_t sector_num, int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
const uint8_t *buf, int nb_sectors); const uint8_t *buf, int nb_sectors);
int blk_truncate(BlockBackend *blk, int64_t offset); int blk_truncate(BlockBackend *blk, int64_t offset);

View File

@ -197,8 +197,8 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
void qemu_sglist_destroy(QEMUSGList *qsg); void qemu_sglist_destroy(QEMUSGList *qsg);
#endif #endif
typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t sector_num, typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t offset,
QEMUIOVector *iov, int nb_sectors, QEMUIOVector *iov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque); BlockCompletionFunc *cb, void *opaque);
BlockAIOCB *dma_blk_io(BlockBackend *blk, BlockAIOCB *dma_blk_io(BlockBackend *blk,

View File

@ -1115,7 +1115,7 @@ static void nbd_trip(void *opaque)
TRACE("Writing to device"); TRACE("Writing to device");
ret = blk_pwrite(exp->blk, request.from + exp->dev_offset, ret = blk_pwrite(exp->blk, request.from + exp->dev_offset,
req->data, request.len); req->data, request.len, 0);
if (ret < 0) { if (ret < 0) {
LOG("writing to file failed"); LOG("writing to file failed");
reply.error = -ret; reply.error = -ret;

View File

@ -2556,3 +2556,35 @@
## ##
{ 'command': 'block-set-write-threshold', { 'command': 'block-set-write-threshold',
'data': { 'node-name': 'str', 'write-threshold': 'uint64' } } 'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
##
# @x-blockdev-change
#
# Dynamically reconfigure the block driver state graph. It can be used
# to add, remove, insert or replace a graph node. Currently only the
# Quorum driver implements this feature to add or remove its child. This
# is useful to fix a broken quorum child.
#
# If @node is specified, it will be inserted under @parent. @child
# may not be specified in this case. If both @parent and @child are
# specified but @node is not, @child will be detached from @parent.
#
# @parent: the id or name of the parent node.
#
# @child: #optional the name of a child under the given parent node.
#
# @node: #optional the name of the node that will be added.
#
# Note: this command is experimental, and its API is not stable. It
# does not support all kinds of operations, all kinds of children, nor
# all block drivers.
#
# Warning: The data in a new quorum child MUST be consistent with that of
# the rest of the array.
#
# Since: 2.7
##
{ 'command': 'x-blockdev-change',
'data' : { 'parent': 'str',
'*child': 'str',
'*node': 'str' } }

View File

@ -693,6 +693,9 @@ Supported options:
File name of a base image (see @option{create} subcommand). File name of a base image (see @option{create} subcommand).
@item compat6 @item compat6
Create a VMDK version 6 image (instead of version 4) Create a VMDK version 6 image (instead of version 4)
@item hwversion
Specify vmdk virtual hardware version. Compat6 flag cannot be enabled
if hwversion is specified.
@item subformat @item subformat
Specifies which VMDK subformat to use. Valid options are Specifies which VMDK subformat to use. Valid options are
@code{monolithicSparse} (default), @code{monolithicSparse} (default),

View File

@ -1088,7 +1088,8 @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
uint8_t *buffer, bool quiet) uint8_t *buffer, bool quiet)
{ {
int pnum, ret = 0; int pnum, ret = 0;
ret = blk_read(blk, sect_num, buffer, sect_count); ret = blk_pread(blk, sect_num << BDRV_SECTOR_BITS, buffer,
sect_count << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
error_report("Error while reading offset %" PRId64 " of %s: %s", error_report("Error while reading offset %" PRId64 " of %s: %s",
sectors_to_bytes(sect_num), filename, strerror(-ret)); sectors_to_bytes(sect_num), filename, strerror(-ret));
@ -1301,7 +1302,8 @@ static int img_compare(int argc, char **argv)
nb_sectors = MIN(pnum1, pnum2); nb_sectors = MIN(pnum1, pnum2);
} else if (allocated1 == allocated2) { } else if (allocated1 == allocated2) {
if (allocated1) { if (allocated1) {
ret = blk_read(blk1, sector_num, buf1, nb_sectors); ret = blk_pread(blk1, sector_num << BDRV_SECTOR_BITS, buf1,
nb_sectors << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
error_report("Error while reading offset %" PRId64 " of %s:" error_report("Error while reading offset %" PRId64 " of %s:"
" %s", sectors_to_bytes(sector_num), filename1, " %s", sectors_to_bytes(sector_num), filename1,
@ -1309,7 +1311,8 @@ static int img_compare(int argc, char **argv)
ret = 4; ret = 4;
goto out; goto out;
} }
ret = blk_read(blk2, sector_num, buf2, nb_sectors); ret = blk_pread(blk2, sector_num << BDRV_SECTOR_BITS, buf2,
nb_sectors << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
error_report("Error while reading offset %" PRId64 error_report("Error while reading offset %" PRId64
" of %s: %s", sectors_to_bytes(sector_num), " of %s: %s", sectors_to_bytes(sector_num),
@ -1472,10 +1475,21 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
} else if (!s->target_has_backing) { } else if (!s->target_has_backing) {
/* Without a target backing file we must copy over the contents of /* Without a target backing file we must copy over the contents of
* the backing file as well. */ * the backing file as well. */
/* TODO Check block status of the backing file chain to avoid /* Check block status of the backing file chain to avoid
* needlessly reading zeroes and limiting the iteration to the * needlessly reading zeroes and limiting the iteration to the
* buffer size */ * buffer size */
s->status = BLK_DATA; ret = bdrv_get_block_status_above(blk_bs(s->src[s->src_cur]), NULL,
sector_num - s->src_cur_offset,
n, &n, &file);
if (ret < 0) {
return ret;
}
if (ret & BDRV_BLOCK_ZERO) {
s->status = BLK_ZERO;
} else {
s->status = BLK_DATA;
}
} else { } else {
s->status = BLK_BACKING_FILE; s->status = BLK_BACKING_FILE;
} }
@ -1522,7 +1536,9 @@ static int convert_read(ImgConvertState *s, int64_t sector_num, int nb_sectors,
bs_sectors = s->src_sectors[s->src_cur]; bs_sectors = s->src_sectors[s->src_cur];
n = MIN(nb_sectors, bs_sectors - (sector_num - s->src_cur_offset)); n = MIN(nb_sectors, bs_sectors - (sector_num - s->src_cur_offset));
ret = blk_read(blk, sector_num - s->src_cur_offset, buf, n); ret = blk_pread(blk,
(sector_num - s->src_cur_offset) << BDRV_SECTOR_BITS,
buf, n << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -1577,7 +1593,8 @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
if (!s->min_sparse || if (!s->min_sparse ||
is_allocated_sectors_min(buf, n, &n, s->min_sparse)) is_allocated_sectors_min(buf, n, &n, s->min_sparse))
{ {
ret = blk_write(s->target, sector_num, buf, n); ret = blk_pwrite(s->target, sector_num << BDRV_SECTOR_BITS,
buf, n << BDRV_SECTOR_BITS, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -1589,7 +1606,8 @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
if (s->has_zero_init) { if (s->has_zero_init) {
break; break;
} }
ret = blk_write_zeroes(s->target, sector_num, n, 0); ret = blk_write_zeroes(s->target, sector_num << BDRV_SECTOR_BITS,
n << BDRV_SECTOR_BITS, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -3023,7 +3041,8 @@ static int img_rebase(int argc, char **argv)
n = old_backing_num_sectors - sector; n = old_backing_num_sectors - sector;
} }
ret = blk_read(blk_old_backing, sector, buf_old, n); ret = blk_pread(blk_old_backing, sector << BDRV_SECTOR_BITS,
buf_old, n << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
error_report("error while reading from old backing file"); error_report("error while reading from old backing file");
goto out; goto out;
@ -3037,7 +3056,8 @@ static int img_rebase(int argc, char **argv)
n = new_backing_num_sectors - sector; n = new_backing_num_sectors - sector;
} }
ret = blk_read(blk_new_backing, sector, buf_new, n); ret = blk_pread(blk_new_backing, sector << BDRV_SECTOR_BITS,
buf_new, n << BDRV_SECTOR_BITS);
if (ret < 0) { if (ret < 0) {
error_report("error while reading from new backing file"); error_report("error while reading from new backing file");
goto out; goto out;
@ -3053,8 +3073,10 @@ static int img_rebase(int argc, char **argv)
if (compare_sectors(buf_old + written * 512, if (compare_sectors(buf_old + written * 512,
buf_new + written * 512, n - written, &pnum)) buf_new + written * 512, n - written, &pnum))
{ {
ret = blk_write(blk, sector + written, ret = blk_pwrite(blk,
buf_old + written * 512, pnum); (sector + written) << BDRV_SECTOR_BITS,
buf_old + written * 512,
pnum << BDRV_SECTOR_BITS, 0);
if (ret < 0) { if (ret < 0) {
error_report("Error while writing to COW image: %s", error_report("Error while writing to COW image: %s",
strerror(-ret)); strerror(-ret));

View File

@ -1,7 +1,7 @@
/* /*
* Command line utility to exercise the QEMU I/O path. * Command line utility to exercise the QEMU I/O path.
* *
* Copyright (C) 2009 Red Hat, Inc. * Copyright (C) 2009-2016 Red Hat, Inc.
* Copyright (c) 2003-2005 Silicon Graphics, Inc. * Copyright (c) 2003-2005 Silicon Graphics, Inc.
* *
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
@ -345,7 +345,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
} }
static void print_report(const char *op, struct timeval *t, int64_t offset, static void print_report(const char *op, struct timeval *t, int64_t offset,
int64_t count, int64_t total, int cnt, int Cflag) int64_t count, int64_t total, int cnt, bool Cflag)
{ {
char s1[64], s2[64], ts[64]; char s1[64], s2[64], ts[64];
@ -395,12 +395,6 @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
goto fail; goto fail;
} }
if (len & 0x1ff) {
printf("length argument %" PRId64
" is not sector aligned\n", len);
goto fail;
}
sizes[i] = len; sizes[i] = len;
count += len; count += len;
} }
@ -419,40 +413,6 @@ fail:
return buf; return buf;
} }
static int do_read(BlockBackend *blk, char *buf, int64_t offset, int64_t count,
int64_t *total)
{
int ret;
if (count >> 9 > INT_MAX) {
return -ERANGE;
}
ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9);
if (ret < 0) {
return ret;
}
*total = count;
return 1;
}
static int do_write(BlockBackend *blk, char *buf, int64_t offset, int64_t count,
int64_t *total)
{
int ret;
if (count >> 9 > INT_MAX) {
return -ERANGE;
}
ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9);
if (ret < 0) {
return ret;
}
*total = count;
return 1;
}
static int do_pread(BlockBackend *blk, char *buf, int64_t offset, static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
int64_t count, int64_t *total) int64_t count, int64_t *total)
{ {
@ -468,13 +428,13 @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
} }
static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
int64_t count, int64_t *total) int64_t count, int flags, int64_t *total)
{ {
if (count > INT_MAX) { if (count > INT_MAX) {
return -ERANGE; return -ERANGE;
} }
*total = blk_pwrite(blk, offset, (uint8_t *)buf, count); *total = blk_pwrite(blk, offset, (uint8_t *)buf, count, flags);
if (*total < 0) { if (*total < 0) {
return *total; return *total;
} }
@ -486,6 +446,7 @@ typedef struct {
int64_t offset; int64_t offset;
int64_t count; int64_t count;
int64_t *total; int64_t *total;
int flags;
int ret; int ret;
bool done; bool done;
} CoWriteZeroes; } CoWriteZeroes;
@ -494,8 +455,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
{ {
CoWriteZeroes *data = opaque; CoWriteZeroes *data = opaque;
data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE, data->ret = blk_co_write_zeroes(data->blk, data->offset, data->count,
data->count / BDRV_SECTOR_SIZE, 0); data->flags);
data->done = true; data->done = true;
if (data->ret < 0) { if (data->ret < 0) {
*data->total = data->ret; *data->total = data->ret;
@ -506,7 +467,7 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
} }
static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count, static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
int64_t *total) int flags, int64_t *total)
{ {
Coroutine *co; Coroutine *co;
CoWriteZeroes data = { CoWriteZeroes data = {
@ -514,6 +475,7 @@ static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
.offset = offset, .offset = offset,
.count = count, .count = count,
.total = total, .total = total,
.flags = flags,
.done = false, .done = false,
}; };
@ -589,8 +551,7 @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
{ {
int async_ret = NOT_DONE; int async_ret = NOT_DONE;
blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9, blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret);
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) { while (async_ret == NOT_DONE) {
main_loop_wait(false); main_loop_wait(false);
} }
@ -600,12 +561,11 @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
} }
static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov, static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
int64_t offset, int *total) int64_t offset, int flags, int *total)
{ {
int async_ret = NOT_DONE; int async_ret = NOT_DONE;
blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9, blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) { while (async_ret == NOT_DONE) {
main_loop_wait(false); main_loop_wait(false);
} }
@ -671,7 +631,7 @@ static void read_help(void)
" -b, -- read from the VM state rather than the virtual disk\n" " -b, -- read from the VM state rather than the virtual disk\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -l, -- length for pattern verification (only with -P)\n" " -l, -- length for pattern verification (only with -P)\n"
" -p, -- use blk_pread to read the file\n" " -p, -- ignored for backwards compatibility\n"
" -P, -- use a pattern to verify read data\n" " -P, -- use a pattern to verify read data\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -s, -- start offset for pattern verification (only with -P)\n" " -s, -- start offset for pattern verification (only with -P)\n"
@ -687,7 +647,7 @@ static const cmdinfo_t read_cmd = {
.cfunc = read_f, .cfunc = read_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", .args = "[-abCqv] [-P pattern [-s off] [-l len]] off len",
.oneline = "reads a number of bytes at a specified offset", .oneline = "reads a number of bytes at a specified offset",
.help = read_help, .help = read_help,
}; };
@ -695,8 +655,8 @@ static const cmdinfo_t read_cmd = {
static int read_f(BlockBackend *blk, int argc, char **argv) static int read_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; bool Cflag = false, qflag = false, vflag = false;
int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; bool Pflag = false, sflag = false, lflag = false, bflag = false;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -709,13 +669,13 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) { while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
bflag = 1; bflag = true;
break; break;
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'l': case 'l':
lflag = 1; lflag = true;
pattern_count = cvtnum(optarg); pattern_count = cvtnum(optarg);
if (pattern_count < 0) { if (pattern_count < 0) {
print_cvtnum_err(pattern_count, optarg); print_cvtnum_err(pattern_count, optarg);
@ -723,20 +683,20 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'p': case 'p':
pflag = 1; /* Ignored for backwards compatibility */
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 's': case 's':
sflag = 1; sflag = true;
pattern_offset = cvtnum(optarg); pattern_offset = cvtnum(optarg);
if (pattern_offset < 0) { if (pattern_offset < 0) {
print_cvtnum_err(pattern_offset, optarg); print_cvtnum_err(pattern_offset, optarg);
@ -744,7 +704,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'v': case 'v':
vflag = 1; vflag = true;
break; break;
default: default:
return qemuio_command_usage(&read_cmd); return qemuio_command_usage(&read_cmd);
@ -755,11 +715,6 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
return qemuio_command_usage(&read_cmd); return qemuio_command_usage(&read_cmd);
} }
if (bflag && pflag) {
printf("-b and -p cannot be specified at the same time\n");
return 0;
}
offset = cvtnum(argv[optind]); offset = cvtnum(argv[optind]);
if (offset < 0) { if (offset < 0) {
print_cvtnum_err(offset, argv[optind]); print_cvtnum_err(offset, argv[optind]);
@ -790,7 +745,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if (!pflag) { if (bflag) {
if (offset & 0x1ff) { if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n", printf("offset %" PRId64 " is not sector aligned\n",
offset); offset);
@ -806,12 +761,10 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
buf = qemu_io_alloc(blk, count, 0xab); buf = qemu_io_alloc(blk, count, 0xab);
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
if (pflag) { if (bflag) {
cnt = do_pread(blk, buf, offset, count, &total);
} else if (bflag) {
cnt = do_load_vmstate(blk, buf, offset, count, &total); cnt = do_load_vmstate(blk, buf, offset, count, &total);
} else { } else {
cnt = do_read(blk, buf, offset, count, &total); cnt = do_pread(blk, buf, offset, count, &total);
} }
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
@ -875,7 +828,7 @@ static const cmdinfo_t readv_cmd = {
.cfunc = readv_f, .cfunc = readv_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cqv] [-P pattern ] off len [len..]", .args = "[-Cqv] [-P pattern] off len [len..]",
.oneline = "reads a number of bytes at a specified offset", .oneline = "reads a number of bytes at a specified offset",
.help = readv_help, .help = readv_help,
}; };
@ -883,7 +836,7 @@ static const cmdinfo_t readv_cmd = {
static int readv_f(BlockBackend *blk, int argc, char **argv) static int readv_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0, vflag = 0; bool Cflag = false, qflag = false, vflag = false;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -892,25 +845,25 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
int nr_iov; int nr_iov;
QEMUIOVector qiov; QEMUIOVector qiov;
int pattern = 0; int pattern = 0;
int Pflag = 0; bool Pflag = false;
while ((c = getopt(argc, argv, "CP:qv")) != -1) { while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'v': case 'v':
vflag = 1; vflag = true;
break; break;
default: default:
return qemuio_command_usage(&readv_cmd); return qemuio_command_usage(&readv_cmd);
@ -929,12 +882,6 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
offset);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
if (buf == NULL) { if (buf == NULL) {
@ -991,10 +938,12 @@ static void write_help(void)
" filled with a set pattern (0xcdcdcdcd).\n" " filled with a set pattern (0xcdcdcdcd).\n"
" -b, -- write to the VM state rather than the virtual disk\n" " -b, -- write to the VM state rather than the virtual disk\n"
" -c, -- write compressed data with blk_write_compressed\n" " -c, -- write compressed data with blk_write_compressed\n"
" -p, -- use blk_pwrite to write the file\n" " -f, -- use Force Unit Access semantics\n"
" -p, -- ignored for backwards compatibility\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
" -z, -- write zeroes using blk_co_write_zeroes\n" " -z, -- write zeroes using blk_co_write_zeroes\n"
"\n"); "\n");
} }
@ -1007,7 +956,7 @@ static const cmdinfo_t write_cmd = {
.cfunc = write_f, .cfunc = write_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-bcCpqz] [-P pattern ] off len", .args = "[-bcCfquz] [-P pattern] off len",
.oneline = "writes a number of bytes at a specified offset", .oneline = "writes a number of bytes at a specified offset",
.help = write_help, .help = write_help,
}; };
@ -1015,8 +964,9 @@ static const cmdinfo_t write_cmd = {
static int write_f(BlockBackend *blk, int argc, char **argv) static int write_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; bool Cflag = false, qflag = false, bflag = false;
int cflag = 0; bool Pflag = false, zflag = false, cflag = false;
int flags = 0;
int c, cnt; int c, cnt;
char *buf = NULL; char *buf = NULL;
int64_t offset; int64_t offset;
@ -1025,32 +975,38 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
int64_t total = 0; int64_t total = 0;
int pattern = 0xcd; int pattern = 0xcd;
while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) { while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
bflag = 1; bflag = true;
break; break;
case 'c': case 'c':
cflag = 1; cflag = true;
break; break;
case 'C': case 'C':
Cflag = 1; Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'p': case 'p':
pflag = 1; /* Ignored for backwards compatibility */
break; break;
case 'P': case 'P':
Pflag = 1; Pflag = true;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) { if (pattern < 0) {
return 0; return 0;
} }
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break;
case 'u':
flags |= BDRV_REQ_MAY_UNMAP;
break; break;
case 'z': case 'z':
zflag = 1; zflag = true;
break; break;
default: default:
return qemuio_command_usage(&write_cmd); return qemuio_command_usage(&write_cmd);
@ -1061,8 +1017,18 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
return qemuio_command_usage(&write_cmd); return qemuio_command_usage(&write_cmd);
} }
if (bflag + pflag + zflag > 1) { if (bflag && zflag) {
printf("-b, -p, or -z cannot be specified at the same time\n"); printf("-b and -z cannot be specified at the same time\n");
return 0;
}
if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) {
printf("-f and -b or -c cannot be specified at the same time\n");
return 0;
}
if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) {
printf("-u requires -z to be specified\n");
return 0; return 0;
} }
@ -1088,7 +1054,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if (!pflag) { if (bflag || cflag) {
if (offset & 0x1ff) { if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n", printf("offset %" PRId64 " is not sector aligned\n",
offset); offset);
@ -1107,16 +1073,14 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
} }
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
if (pflag) { if (bflag) {
cnt = do_pwrite(blk, buf, offset, count, &total);
} else if (bflag) {
cnt = do_save_vmstate(blk, buf, offset, count, &total); cnt = do_save_vmstate(blk, buf, offset, count, &total);
} else if (zflag) { } else if (zflag) {
cnt = do_co_write_zeroes(blk, offset, count, &total); cnt = do_co_write_zeroes(blk, offset, count, flags, &total);
} else if (cflag) { } else if (cflag) {
cnt = do_write_compressed(blk, buf, offset, count, &total); cnt = do_write_compressed(blk, buf, offset, count, &total);
} else { } else {
cnt = do_write(blk, buf, offset, count, &total); cnt = do_pwrite(blk, buf, offset, count, flags, &total);
} }
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
@ -1155,6 +1119,7 @@ writev_help(void)
" filled with a set pattern (0xcdcdcdcd).\n" " filled with a set pattern (0xcdcdcdcd).\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -f, -- use Force Unit Access semantics\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
"\n"); "\n");
} }
@ -1166,7 +1131,7 @@ static const cmdinfo_t writev_cmd = {
.cfunc = writev_f, .cfunc = writev_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cq] [-P pattern ] off len [len..]", .args = "[-Cfq] [-P pattern] off len [len..]",
.oneline = "writes a number of bytes at a specified offset", .oneline = "writes a number of bytes at a specified offset",
.help = writev_help, .help = writev_help,
}; };
@ -1174,7 +1139,8 @@ static const cmdinfo_t writev_cmd = {
static int writev_f(BlockBackend *blk, int argc, char **argv) static int writev_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int flags = 0;
int c, cnt; int c, cnt;
char *buf; char *buf;
int64_t offset; int64_t offset;
@ -1187,10 +1153,13 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CqP:")) != -1) { while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1214,12 +1183,6 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
offset);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
if (buf == NULL) { if (buf == NULL) {
@ -1227,7 +1190,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
} }
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
cnt = do_aio_writev(blk, &qiov, offset, &total); cnt = do_aio_writev(blk, &qiov, offset, flags, &total);
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
if (cnt < 0) { if (cnt < 0) {
@ -1283,7 +1246,7 @@ static const cmdinfo_t multiwrite_cmd = {
static int multiwrite_f(BlockBackend *blk, int argc, char **argv) static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int c, cnt; int c, cnt;
char **buf; char **buf;
int64_t offset, first_offset = 0; int64_t offset, first_offset = 0;
@ -1299,10 +1262,10 @@ static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CqP:")) != -1) { while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1412,11 +1375,11 @@ struct aio_ctx {
QEMUIOVector qiov; QEMUIOVector qiov;
int64_t offset; int64_t offset;
char *buf; char *buf;
int qflag; bool qflag;
int vflag; bool vflag;
int Cflag; bool Cflag;
int Pflag; bool Pflag;
int zflag; bool zflag;
BlockAcctCookie acct; BlockAcctCookie acct;
int pattern; int pattern;
struct timeval t1; struct timeval t1;
@ -1525,7 +1488,7 @@ static const cmdinfo_t aio_read_cmd = {
.cfunc = aio_read_f, .cfunc = aio_read_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cqv] [-P pattern ] off len [len..]", .args = "[-Cqv] [-P pattern] off len [len..]",
.oneline = "asynchronously reads a number of bytes", .oneline = "asynchronously reads a number of bytes",
.help = aio_read_help, .help = aio_read_help,
}; };
@ -1539,10 +1502,10 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
while ((c = getopt(argc, argv, "CP:qv")) != -1) { while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
ctx->Cflag = 1; ctx->Cflag = true;
break; break;
case 'P': case 'P':
ctx->Pflag = 1; ctx->Pflag = true;
ctx->pattern = parse_pattern(optarg); ctx->pattern = parse_pattern(optarg);
if (ctx->pattern < 0) { if (ctx->pattern < 0) {
g_free(ctx); g_free(ctx);
@ -1550,10 +1513,10 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'q': case 'q':
ctx->qflag = 1; ctx->qflag = true;
break; break;
case 'v': case 'v':
ctx->vflag = 1; ctx->vflag = true;
break; break;
default: default:
g_free(ctx); g_free(ctx);
@ -1574,14 +1537,6 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
g_free(ctx);
return 0;
}
nr_iov = argc - optind; nr_iov = argc - optind;
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab); ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
if (ctx->buf == NULL) { if (ctx->buf == NULL) {
@ -1593,8 +1548,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
gettimeofday(&ctx->t1, NULL); gettimeofday(&ctx->t1, NULL);
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
BLOCK_ACCT_READ); BLOCK_ACCT_READ);
blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov, blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
ctx->qiov.size >> 9, aio_read_done, ctx);
return 0; return 0;
} }
@ -1614,7 +1568,9 @@ static void aio_write_help(void)
" used to ensure all outstanding aio requests have been completed.\n" " used to ensure all outstanding aio requests have been completed.\n"
" -P, -- use different pattern to fill file\n" " -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n" " -C, -- report statistics in a machine parsable format\n"
" -f, -- use Force Unit Access semantics\n"
" -q, -- quiet mode, do not show I/O statistics\n" " -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
" -z, -- write zeroes using blk_aio_write_zeroes\n" " -z, -- write zeroes using blk_aio_write_zeroes\n"
"\n"); "\n");
} }
@ -1626,7 +1582,7 @@ static const cmdinfo_t aio_write_cmd = {
.cfunc = aio_write_f, .cfunc = aio_write_f,
.argmin = 2, .argmin = 2,
.argmax = -1, .argmax = -1,
.args = "[-Cqz] [-P pattern ] off len [len..]", .args = "[-Cfquz] [-P pattern] off len [len..]",
.oneline = "asynchronously writes a number of bytes", .oneline = "asynchronously writes a number of bytes",
.help = aio_write_help, .help = aio_write_help,
}; };
@ -1636,15 +1592,22 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
int nr_iov, c; int nr_iov, c;
int pattern = 0xcd; int pattern = 0xcd;
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
int flags = 0;
ctx->blk = blk; ctx->blk = blk;
while ((c = getopt(argc, argv, "CqP:z")) != -1) { while ((c = getopt(argc, argv, "CfqP:z")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
ctx->Cflag = 1; ctx->Cflag = true;
break;
case 'f':
flags |= BDRV_REQ_FUA;
break; break;
case 'q': case 'q':
ctx->qflag = 1; ctx->qflag = true;
break;
case 'u':
flags |= BDRV_REQ_MAY_UNMAP;
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
@ -1654,7 +1617,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
} }
break; break;
case 'z': case 'z':
ctx->zflag = 1; ctx->zflag = true;
break; break;
default: default:
g_free(ctx); g_free(ctx);
@ -1673,6 +1636,11 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
return 0; return 0;
} }
if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
printf("-u requires -z to be specified\n");
return 0;
}
if (ctx->zflag && ctx->Pflag) { if (ctx->zflag && ctx->Pflag) {
printf("-z and -P cannot be specified at the same time\n"); printf("-z and -P cannot be specified at the same time\n");
g_free(ctx); g_free(ctx);
@ -1687,24 +1655,17 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
} }
optind++; optind++;
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
g_free(ctx);
return 0;
}
if (ctx->zflag) { if (ctx->zflag) {
int64_t count = cvtnum(argv[optind]); int64_t count = cvtnum(argv[optind]);
if (count < 0) { if (count < 0) {
print_cvtnum_err(count, argv[optind]); print_cvtnum_err(count, argv[optind]);
g_free(ctx);
return 0; return 0;
} }
ctx->qiov.size = count; ctx->qiov.size = count;
blk_aio_write_zeroes(blk, ctx->offset >> 9, count >> 9, 0, blk_aio_write_zeroes(blk, ctx->offset, count, flags, aio_write_done,
aio_write_done, ctx); ctx);
} else { } else {
nr_iov = argc - optind; nr_iov = argc - optind;
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
@ -1719,8 +1680,8 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
BLOCK_ACCT_WRITE); BLOCK_ACCT_WRITE);
blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov, blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
ctx->qiov.size >> 9, aio_write_done, ctx); ctx);
} }
return 0; return 0;
} }
@ -1884,17 +1845,17 @@ static const cmdinfo_t discard_cmd = {
static int discard_f(BlockBackend *blk, int argc, char **argv) static int discard_f(BlockBackend *blk, int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; bool Cflag = false, qflag = false;
int c, ret; int c, ret;
int64_t offset, count; int64_t offset, count;
while ((c = getopt(argc, argv, "Cq")) != -1) { while ((c = getopt(argc, argv, "Cq")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
Cflag = 1; Cflag = true;
break; break;
case 'q': case 'q':
qflag = 1; qflag = true;
break; break;
default: default:
return qemuio_command_usage(&discard_cmd); return qemuio_command_usage(&discard_cmd);

View File

@ -101,12 +101,15 @@ static void open_help(void)
" opens a new file in the requested mode\n" " opens a new file in the requested mode\n"
"\n" "\n"
" Example:\n" " Example:\n"
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" " 'open -n -o driver=raw /tmp/data' - opens raw data file read-write, uncached\n"
"\n" "\n"
" Opens a file for subsequent use by all of the other qemu-io commands.\n" " Opens a file for subsequent use by all of the other qemu-io commands.\n"
" -r, -- open file read-only\n" " -r, -- open file read-only\n"
" -s, -- use snapshot file\n" " -s, -- use snapshot file\n"
" -n, -- disable host cache\n" " -n, -- disable host cache, short for -t none\n"
" -k, -- use kernel AIO implementation (on Linux only)\n"
" -t, -- use the given cache mode for the image\n"
" -d, -- use the given discard mode for the image\n"
" -o, -- options to be given to the block driver" " -o, -- options to be given to the block driver"
"\n"); "\n");
} }
@ -120,7 +123,7 @@ static const cmdinfo_t open_cmd = {
.argmin = 1, .argmin = 1,
.argmax = -1, .argmax = -1,
.flags = CMD_NOFILE_OK, .flags = CMD_NOFILE_OK,
.args = "[-Crsn] [-o options] [path]", .args = "[-rsnk] [-t cache] [-d discard] [-o options] [path]",
.oneline = "open the file specified by path", .oneline = "open the file specified by path",
.help = open_help, .help = open_help,
}; };
@ -137,14 +140,14 @@ static QemuOptsList empty_opts = {
static int open_f(BlockBackend *blk, int argc, char **argv) static int open_f(BlockBackend *blk, int argc, char **argv)
{ {
int flags = 0; int flags = BDRV_O_UNMAP;
int readonly = 0; int readonly = 0;
bool writethrough = true; bool writethrough = true;
int c; int c;
QemuOpts *qopts; QemuOpts *qopts;
QDict *opts; QDict *opts;
while ((c = getopt(argc, argv, "snrgo:")) != -1) { while ((c = getopt(argc, argv, "snro:kt:d:")) != -1) {
switch (c) { switch (c) {
case 's': case 's':
flags |= BDRV_O_SNAPSHOT; flags |= BDRV_O_SNAPSHOT;
@ -156,9 +159,27 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
case 'r': case 'r':
readonly = 1; readonly = 1;
break; break;
case 'k':
flags |= BDRV_O_NATIVE_AIO;
break;
case 't':
if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
error_report("Invalid cache option: %s", optarg);
qemu_opts_reset(&empty_opts);
return 0;
}
break;
case 'd':
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
error_report("Invalid discard option: %s", optarg);
qemu_opts_reset(&empty_opts);
return 0;
}
break;
case 'o': case 'o':
if (imageOpts) { if (imageOpts) {
printf("--image-opts and 'open -o' are mutually exclusive\n"); printf("--image-opts and 'open -o' are mutually exclusive\n");
qemu_opts_reset(&empty_opts);
return 0; return 0;
} }
if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) {
@ -216,20 +237,22 @@ static const cmdinfo_t quit_cmd = {
static void usage(const char *name) static void usage(const char *name)
{ {
printf( printf(
"Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n" "Usage: %s [OPTIONS]... [-c STRING]... [file]\n"
"QEMU Disk exerciser\n" "QEMU Disk exerciser\n"
"\n" "\n"
" --object OBJECTDEF define an object such as 'secret' for\n" " --object OBJECTDEF define an object such as 'secret' for\n"
" passwords and/or encryption keys\n" " passwords and/or encryption keys\n"
" --image-opts treat file as option string\n"
" -c, --cmd STRING execute command with its arguments\n" " -c, --cmd STRING execute command with its arguments\n"
" from the given string\n" " from the given string\n"
" -f, --format FMT specifies the block driver to use\n" " -f, --format FMT specifies the block driver to use\n"
" -r, --read-only export read-only\n" " -r, --read-only export read-only\n"
" -s, --snapshot use snapshot file\n" " -s, --snapshot use snapshot file\n"
" -n, --nocache disable host cache\n" " -n, --nocache disable host cache, short for -t none\n"
" -m, --misalign misalign allocations for O_DIRECT\n" " -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n" " -k, --native-aio use kernel AIO implementation (on Linux only)\n"
" -t, --cache=MODE use the given cache mode for the image\n" " -t, --cache=MODE use the given cache mode for the image\n"
" -d, --discard=MODE use the given discard mode for the image\n"
" -T, --trace FILE enable trace events listed in the given file\n" " -T, --trace FILE enable trace events listed in the given file\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
@ -410,11 +433,10 @@ static QemuOptsList file_opts = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int readonly = 0; int readonly = 0;
const char *sopt = "hVc:d:f:rsnmgkt:T:"; const char *sopt = "hVc:d:f:rsnmkt:T:";
const struct option lopt[] = { const struct option lopt[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "offset", required_argument, NULL, 'o' },
{ "cmd", required_argument, NULL, 'c' }, { "cmd", required_argument, NULL, 'c' },
{ "format", required_argument, NULL, 'f' }, { "format", required_argument, NULL, 'f' },
{ "read-only", no_argument, NULL, 'r' }, { "read-only", no_argument, NULL, 'r' },

View File

@ -46,6 +46,8 @@
#define QEMU_NBD_OPT_TLSCREDS 261 #define QEMU_NBD_OPT_TLSCREDS 261
#define QEMU_NBD_OPT_IMAGE_OPTS 262 #define QEMU_NBD_OPT_IMAGE_OPTS 262
#define MBR_SIZE 512
static NBDExport *exp; static NBDExport *exp;
static bool newproto; static bool newproto;
static int verbose; static int verbose;
@ -159,12 +161,13 @@ static int find_partition(BlockBackend *blk, int partition,
off_t *offset, off_t *size) off_t *offset, off_t *size)
{ {
struct partition_record mbr[4]; struct partition_record mbr[4];
uint8_t data[512]; uint8_t data[MBR_SIZE];
int i; int i;
int ext_partnum = 4; int ext_partnum = 4;
int ret; int ret;
if ((ret = blk_read(blk, 0, data, 1)) < 0) { ret = blk_pread(blk, 0, data, sizeof(data));
if (ret < 0) {
error_report("error while reading: %s", strerror(-ret)); error_report("error while reading: %s", strerror(-ret));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -182,10 +185,12 @@ static int find_partition(BlockBackend *blk, int partition,
if (mbr[i].system == 0xF || mbr[i].system == 0x5) { if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
struct partition_record ext[4]; struct partition_record ext[4];
uint8_t data1[512]; uint8_t data1[MBR_SIZE];
int j; int j;
if ((ret = blk_read(blk, mbr[i].start_sector_abs, data1, 1)) < 0) { ret = blk_pread(blk, mbr[i].start_sector_abs * MBR_SIZE,
data1, sizeof(data1));
if (ret < 0) {
error_report("error while reading: %s", strerror(-ret)); error_report("error while reading: %s", strerror(-ret));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -4395,6 +4395,59 @@ Example:
<- { "return": {} } <- { "return": {} }
EQMP
{
.name = "x-blockdev-change",
.args_type = "parent:B,child:B?,node:B?",
.mhandler.cmd_new = qmp_marshal_x_blockdev_change,
},
SQMP
x-blockdev-change
-----------------
Dynamically reconfigure the block driver state graph. It can be used
to add, remove, insert or replace a graph node. Currently only the
Quorum driver implements this feature to add or remove its child. This
is useful to fix a broken quorum child.
If @node is specified, it will be inserted under @parent. @child
may not be specified in this case. If both @parent and @child are
specified but @node is not, @child will be detached from @parent.
Arguments:
- "parent": the id or name of the parent node (json-string)
- "child": the name of a child under the given parent node (json-string, optional)
- "node": the name of the node that will be added (json-string, optional)
Note: this command is experimental, and not a stable API. It doesn't
support all kinds of operations, all kinds of children, nor all block
drivers.
Warning: The data in a new quorum child MUST be consistent with that of
the rest of the array.
Example:
Add a new node to a quorum
-> { "execute": "blockdev-add",
"arguments": { "options": { "driver": "raw",
"node-name": "new_node",
"file": { "driver": "file",
"filename": "test.raw" } } } }
<- { "return": {} }
-> { "execute": "x-blockdev-change",
"arguments": { "parent": "disk1",
"node": "new_node" } }
<- { "return": {} }
Delete a quorum's node
-> { "execute": "x-blockdev-change",
"arguments": { "parent": "disk1",
"child": "children.1" } }
<- { "return": {} }
EQMP EQMP
{ {

View File

@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc . ./common.rc
. ./common.filter . ./common.filter
_supported_fmt raw qcow qcow2 qed vdi vmdk vhdx _supported_fmt raw qcow qcow2 qed vdi vmdk vhdx luks
_supported_proto generic _supported_proto generic
_supported_os Linux _supported_os Linux

View File

@ -43,13 +43,16 @@ _supported_fmt generic
_supported_proto file _supported_proto file
_supported_os Linux _supported_os Linux
# Remove once all tests are fixed to use TEST_IMG_FILE
# correctly and common.rc sets it unconditionally
test -z "$TEST_IMG_FILE" && TEST_IMG_FILE=$TEST_IMG
size=128M size=128M
_make_test_img $size _make_test_img $size
echo echo
echo "== mark image read-only" echo "== mark image read-only"
chmod a-w "$TEST_IMG" chmod a-w "$TEST_IMG_FILE"
echo echo
echo "== read from read-only image" echo "== read from read-only image"

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -51,9 +51,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -69,9 +69,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.
@ -92,9 +92,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x1 incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1 ERROR cluster 5 refcount=0 reference=1
@ -106,9 +106,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.

View File

@ -31,13 +31,13 @@ _cleanup()
{ {
echo "Cleanup" echo "Cleanup"
_cleanup_test_img _cleanup_test_img
rm "${TEST_IMG2}" rm "${TEST_IMG_FILE2}"
} }
trap "_cleanup; exit \$status" 0 1 2 3 15 trap "_cleanup; exit \$status" 0 1 2 3 15
_compare() _compare()
{ {
$QEMU_IMG compare "$@" "$TEST_IMG" "${TEST_IMG2}" $QEMU_IMG compare $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" "${TEST_IMG2}"
echo $? echo $?
} }
@ -46,25 +46,37 @@ _compare()
. ./common.filter . ./common.filter
. ./common.pattern . ./common.pattern
_supported_fmt raw qcow qcow2 qed _supported_fmt raw qcow qcow2 qed luks
_supported_proto file _supported_proto file
_supported_os Linux _supported_os Linux
# Remove once all tests are fixed to use TEST_IMG_FILE
# correctly and common.rc sets it unconditionally
test -z "$TEST_IMG_FILE" && TEST_IMG_FILE=$TEST_IMG
# Setup test basic parameters # Setup test basic parameters
TEST_IMG2=$TEST_IMG.2 TEST_IMG2=$TEST_IMG.2
TEST_IMG_FILE2=$TEST_IMG_FILE.2
CLUSTER_SIZE=4096 CLUSTER_SIZE=4096
size=1024M size=128M
_make_test_img $size _make_test_img $size
io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45 io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45
# Compare identical images # Compare identical images
cp "$TEST_IMG" "${TEST_IMG2}" cp "$TEST_IMG_FILE" "${TEST_IMG_FILE2}"
_compare _compare
_compare -q _compare -q
# Compare images with different size # Compare images with different size
$QEMU_IMG resize -f $IMGFMT "$TEST_IMG" +512M if [ "$IMGOPTSSYNTAX" = "true" ]; then
$QEMU_IMG resize $QEMU_IMG_EXTRA_ARGS "$TEST_IMG" +32M
else
$QEMU_IMG resize -f $IMGFMT "$TEST_IMG" +32M
fi
# Ensure extended space is zero-initialized
$QEMU_IO "$TEST_IMG" -c "write -z $size 32M" | _filter_qemu_io
_compare _compare
_compare -s _compare -s
@ -77,7 +89,7 @@ _compare
# Test unaligned case of mismatch offsets in allocated clusters # Test unaligned case of mismatch offsets in allocated clusters
_make_test_img $size _make_test_img $size
io_pattern write 0 512 0 1 100 io_pattern write 0 512 0 1 100
cp "$TEST_IMG" "$TEST_IMG2" cp "$TEST_IMG_FILE" "$TEST_IMG_FILE2"
io_pattern write 512 512 0 1 101 io_pattern write 512 512 0 1 101
_compare _compare

View File

@ -1,5 +1,5 @@
QA output created by 048 QA output created by 048
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== IO: pattern 45 === IO: pattern 45
wrote 4096/4096 bytes at offset 524288 wrote 4096/4096 bytes at offset 524288
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -13,6 +13,8 @@ Images are identical.
0 0
0 0
Image resized. Image resized.
wrote 33554432/33554432 bytes at offset 134217728
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Warning: Image size mismatch! Warning: Image size mismatch!
Images are identical. Images are identical.
0 0
@ -28,7 +30,7 @@ wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Content mismatch at offset 0! Content mismatch at offset 0!
1 1
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== IO: pattern 100 === IO: pattern 100
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -47,6 +47,10 @@ _supported_cache_modes "writeback" "writethrough" "unsafe"
size=128M size=128M
_make_test_img $size _make_test_img $size
echo
echo "== initializing whole image =="
$QEMU_IO -c "write -z 0 $size" "$TEST_IMG" | _filter_qemu_io
echo echo
echo "== reading whole image ==" echo "== reading whole image =="
$QEMU_IO -s -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -s -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io

View File

@ -1,6 +1,10 @@
QA output created by 052 QA output created by 052
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
== initializing whole image ==
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== reading whole image == == reading whole image ==
read 134217728/134217728 bytes at offset 0 read 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -58,9 +58,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0 wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
magic 0x514649fb magic 0x514649fb
version 3 version 3
@ -220,9 +220,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0 wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
magic 0x514649fb magic 0x514649fb
version 3 version 3

View File

@ -43,7 +43,7 @@ choose_tcp_port() {
wait_for_tcp_port() { wait_for_tcp_port() {
while ! (netstat --tcp --listening --numeric | \ while ! (netstat --tcp --listening --numeric | \
grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") 2>&1 >/dev/null; do grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do
sleep 0.1 sleep 0.1
done done
} }
@ -70,7 +70,7 @@ EOF
nbd_url="nbd:127.0.0.1:$port:exportname=foo" nbd_url="nbd:127.0.0.1:$port:exportname=foo"
fi fi
$PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 &
wait_for_tcp_port "127\\.0\\.0\\.1:$port" wait_for_tcp_port "127\\.0\\.0\\.1:$port"
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd

View File

@ -47,6 +47,7 @@ size=128M
echo echo
echo "== Single request ==" echo "== Single request =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -59,6 +60,7 @@ _cleanup_test_img
echo echo
echo "== Sequential requests ==" echo "== Sequential requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 12k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 4k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 4k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -72,6 +74,7 @@ _cleanup_test_img
echo echo
echo "== Superset overlapping requests ==" echo "== Superset overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 1k 2k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 1k 2k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -87,6 +90,7 @@ _cleanup_test_img
echo echo
echo "== Subset overlapping requests ==" echo "== Subset overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 1k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 1k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -102,6 +106,7 @@ _cleanup_test_img
echo echo
echo "== Head overlapping requests ==" echo "== Head overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -116,6 +121,7 @@ _cleanup_test_img
echo echo
echo "== Tail overlapping requests ==" echo "== Tail overlapping requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 2k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 2k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo
@ -130,6 +136,7 @@ _cleanup_test_img
echo echo
echo "== Disjoint requests ==" echo "== Disjoint requests =="
_make_test_img $size _make_test_img $size
$QEMU_IO -c "write -z 0 72k" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "multiwrite 0 4k ; 64k 4k" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "multiwrite 0 4k ; 64k 4k" "$TEST_IMG" | _filter_qemu_io
echo echo

View File

@ -2,6 +2,8 @@ QA output created by 100
== Single request == == Single request ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 4096/4096 bytes at offset 0 wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -13,6 +15,8 @@ read 4096/4096 bytes at offset 4096
== Sequential requests == == Sequential requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 12288/12288 bytes at offset 0
12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 8192/8192 bytes at offset 0 wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -26,6 +30,8 @@ read 4096/4096 bytes at offset 8192
== Superset overlapping requests == == Superset overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 0 wrote 6144/6144 bytes at offset 0
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -39,6 +45,8 @@ read 4096/4096 bytes at offset 4096
== Subset overlapping requests == == Subset overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 1024 wrote 6144/6144 bytes at offset 1024
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -52,6 +60,8 @@ read 4096/4096 bytes at offset 4096
== Head overlapping requests == == Head overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 0 wrote 6144/6144 bytes at offset 0
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -63,6 +73,8 @@ read 4096/4096 bytes at offset 4096
== Tail overlapping requests == == Tail overlapping requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 6144/6144 bytes at offset 2048 wrote 6144/6144 bytes at offset 2048
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@ -74,6 +86,8 @@ read 4096/4096 bytes at offset 4096
== Disjoint requests == == Disjoint requests ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 73728/73728 bytes at offset 0
72 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 8192/8192 bytes at offset 0 wrote 8192/8192 bytes at offset 0
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

View File

@ -32,9 +32,9 @@ Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of t
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then ./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"; exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
fi ) fi )
incompatible_features 0x0 incompatible_features 0x0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864

View File

@ -53,6 +53,8 @@ export QEMU_IO_OPTIONS=""
export CACHEMODE_IS_DEFAULT=true export CACHEMODE_IS_DEFAULT=true
export QEMU_OPTIONS="-nodefaults" export QEMU_OPTIONS="-nodefaults"
export VALGRIND_QEMU= export VALGRIND_QEMU=
export IMGKEYSECRET=
export IMGOPTSSYNTAX=false
for r for r
do do
@ -207,6 +209,13 @@ testlist options
xpand=false xpand=false
;; ;;
-luks)
IMGOPTSSYNTAX=true
IMGFMT=luks
IMGKEYSECRET=123456
xpand=false
;;
-qed) -qed)
IMGFMT=qed IMGFMT=qed
xpand=false xpand=false
@ -399,7 +408,11 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
done done
# Set qemu-io cache mode with $CACHEMODE we have # Set qemu-io cache mode with $CACHEMODE we have
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE" if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
else
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE"
fi
# Set default options for qemu-img create -o if they were not specified # Set default options for qemu-img create -o if they were not specified
_set_default_imgopts _set_default_imgopts

View File

@ -123,12 +123,19 @@ _qemu_img_wrapper()
_qemu_io_wrapper() _qemu_io_wrapper()
{ {
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
fi
fi
local RETVAL local RETVAL
( (
if [ "${VALGRIND_QEMU}" == "y" ]; then if [ "${VALGRIND_QEMU}" == "y" ]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
else else
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
fi fi
) )
RETVAL=$? RETVAL=$?
@ -154,6 +161,16 @@ export QEMU_IMG=_qemu_img_wrapper
export QEMU_IO=_qemu_io_wrapper export QEMU_IO=_qemu_io_wrapper
export QEMU_NBD=_qemu_nbd_wrapper export QEMU_NBD=_qemu_nbd_wrapper
QEMU_IMG_EXTRA_ARGS=
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
fi
fi
export QEMU_IMG_EXTRA_ARGS
default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p') default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p')
default_alias_machine=$($QEMU -machine help | \ default_alias_machine=$($QEMU -machine help | \
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")

View File

@ -92,12 +92,14 @@ _filter_img_create()
-e "s# zeroed_grain=\\(on\\|off\\)##g" \ -e "s# zeroed_grain=\\(on\\|off\\)##g" \
-e "s# subformat='[^']*'##g" \ -e "s# subformat='[^']*'##g" \
-e "s# adapter_type='[^']*'##g" \ -e "s# adapter_type='[^']*'##g" \
-e "s# hwversion=[^ ]*##g" \
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \ -e "s# lazy_refcounts=\\(on\\|off\\)##g" \
-e "s# block_size=[0-9]\\+##g" \ -e "s# block_size=[0-9]\\+##g" \
-e "s# block_state_zero=\\(on\\|off\\)##g" \ -e "s# block_state_zero=\\(on\\|off\\)##g" \
-e "s# log_size=[0-9]\\+##g" \ -e "s# log_size=[0-9]\\+##g" \
-e "s/archipelago:a/TEST_DIR\//g" \ -e "s/archipelago:a/TEST_DIR\//g" \
-e "s# refcount_bits=[0-9]\\+##g" -e "s# refcount_bits=[0-9]\\+##g" \
-e "s# key-secret=[a-zA-Z0-9]\\+##g"
} }
_filter_img_info() _filter_img_info()
@ -115,6 +117,7 @@ _filter_img_info()
-e "/zeroed_grain: \\(on\\|off\\)/d" \ -e "/zeroed_grain: \\(on\\|off\\)/d" \
-e "/subformat: '[^']*'/d" \ -e "/subformat: '[^']*'/d" \
-e "/adapter_type: '[^']*'/d" \ -e "/adapter_type: '[^']*'/d" \
-e "/hwversion: '[^']*'/d" \
-e "/lazy_refcounts: \\(on\\|off\\)/d" \ -e "/lazy_refcounts: \\(on\\|off\\)/d" \
-e "/block_size: [0-9]\\+/d" \ -e "/block_size: [0-9]\\+/d" \
-e "/block_state_zero: \\(on\\|off\\)/d" \ -e "/block_state_zero: \\(on\\|off\\)/d" \

View File

@ -53,21 +53,45 @@ fi
# make sure we have a standard umask # make sure we have a standard umask
umask 022 umask 022
if [ "$IMGPROTO" = "file" ]; then if [ "$IMGOPTSSYNTAX" = "true" ]; then
TEST_IMG=$TEST_DIR/t.$IMGFMT DRIVER="driver=$IMGFMT"
elif [ "$IMGPROTO" = "nbd" ]; then if [ "$IMGFMT" = "luks" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT DRIVER="$DRIVER,key-secret=keysec0"
TEST_IMG="nbd:127.0.0.1:10810" fi
elif [ "$IMGPROTO" = "ssh" ]; then if [ "$IMGPROTO" = "file" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE" TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
elif [ "$IMGPROTO" = "nfs" ]; then elif [ "$IMGPROTO" = "nbd" ]; then
TEST_DIR="nfs://127.0.0.1/$TEST_DIR" TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG=$TEST_DIR/t.$IMGFMT TEST_IMG="$DRIVER,file.driver=nbd,file.host=127.0.0.1,file.port=10810"
elif [ "$IMGPROTO" = "archipelago" ]; then elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG="archipelago:at.$IMGFMT" TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_DIR="$DRIVER,file.driver=nfs,file.filename=nfs://127.0.0.1/$TEST_DIR"
TEST_IMG=$TEST_DIR_OPTS/t.$IMGFMT
elif [ "$IMGPROTO" = "archipelago" ]; then
TEST_IMG="$DRIVER,file.driver=archipelago,file.volume=:at.$IMGFMT"
else
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
fi
else else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT if [ "$IMGPROTO" = "file" ]; then
TEST_IMG=$TEST_DIR/t.$IMGFMT
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="nbd:127.0.0.1:10810"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
TEST_IMG=$TEST_DIR/t.$IMGFMT
elif [ "$IMGPROTO" = "archipelago" ]; then
TEST_IMG="archipelago:at.$IMGFMT"
else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
fi fi
_optstr_add() _optstr_add()
@ -108,6 +132,7 @@ _make_test_img()
local img_name="" local img_name=""
local use_backing=0 local use_backing=0
local backing_file="" local backing_file=""
local object_options=""
if [ -n "$TEST_IMG_FILE" ]; then if [ -n "$TEST_IMG_FILE" ]; then
img_name=$TEST_IMG_FILE img_name=$TEST_IMG_FILE
@ -118,6 +143,10 @@ _make_test_img()
if [ -n "$IMGOPTS" ]; then if [ -n "$IMGOPTS" ]; then
optstr=$(_optstr_add "$optstr" "$IMGOPTS") optstr=$(_optstr_add "$optstr" "$IMGOPTS")
fi fi
if [ -n "$IMGKEYSECRET" ]; then
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
fi
if [ "$1" = "-b" ]; then if [ "$1" = "-b" ]; then
use_backing=1 use_backing=1
@ -135,9 +164,9 @@ _make_test_img()
# XXX(hch): have global image options? # XXX(hch): have global image options?
( (
if [ $use_backing = 1 ]; then if [ $use_backing = 1 ]; then
$QEMU_IMG create -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1 $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
else else
$QEMU_IMG create -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1 $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
fi fi
) | _filter_img_create ) | _filter_img_create
@ -199,7 +228,13 @@ _cleanup_test_img()
_check_test_img() _check_test_img()
{ {
$QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1 | _filter_testdir | \ (
if [ "$IMGOPTSSYNTAX" = "true" ]; then
$QEMU_IMG check $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1
else
$QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1
fi
) | _filter_testdir | \
sed -e '/allocated.*fragmented.*compressed clusters/d' \ sed -e '/allocated.*fragmented.*compressed clusters/d' \
-e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
-e '/Image end offset: [0-9]\+/d' -e '/Image end offset: [0-9]\+/d'

View File

@ -47,7 +47,7 @@ if os.environ.get('QEMU_OPTIONS'):
imgfmt = os.environ.get('IMGFMT', 'raw') imgfmt = os.environ.get('IMGFMT', 'raw')
imgproto = os.environ.get('IMGPROTO', 'file') imgproto = os.environ.get('IMGPROTO', 'file')
test_dir = os.environ.get('TEST_DIR', '/var/tmp') test_dir = os.environ.get('TEST_DIR')
output_dir = os.environ.get('OUTPUT_DIR', '.') output_dir = os.environ.get('OUTPUT_DIR', '.')
cachemode = os.environ.get('CACHEMODE') cachemode = os.environ.get('CACHEMODE')
qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE') qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE')
@ -461,6 +461,14 @@ def verify_quorum():
def main(supported_fmts=[], supported_oses=['linux']): def main(supported_fmts=[], supported_oses=['linux']):
'''Run tests''' '''Run tests'''
# We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to
# indicate that we're not being run via "check". There may be
# other things set up by "check" that individual test cases rely
# on.
if test_dir is None or qemu_default_machine is None:
sys.stderr.write('Please run this test via the "check" script\n')
sys.exit(os.EX_USAGE)
debug = '-d' in sys.argv debug = '-d' in sys.argv
verbosity = 1 verbosity = 1
verify_image_format(supported_fmts) verify_image_format(supported_fmts)

View File

@ -74,7 +74,6 @@ bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector
bdrv_co_readv_no_serialising(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_readv_no_serialising(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d" bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector, int flags) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x" bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector, int flags) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x"
bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d" bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
# block/stream.c # block/stream.c
@ -119,7 +118,7 @@ virtio_blk_req_complete(void *req, int status) "req %p status %d"
virtio_blk_rw_complete(void *req, int ret) "req %p ret %d" virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t sector, size_t nsectors, bool is_write) "mrb %p start %d num_reqs %d sector %"PRIu64" nsectors %zu is_write %d" virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d"
# hw/block/dataplane/virtio-blk.c # hw/block/dataplane/virtio-blk.c
virtio_blk_data_plane_start(void *s) "dataplane %p" virtio_blk_data_plane_start(void *s) "dataplane %p"