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:
commit
f68419eee9
127
block.c
127
block.c
@ -218,8 +218,6 @@ void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
bdrv_setup_io_funcs(bdrv);
|
||||
|
||||
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
|
||||
}
|
||||
|
||||
@ -1176,10 +1174,10 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
return child;
|
||||
}
|
||||
|
||||
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role)
|
||||
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role)
|
||||
{
|
||||
BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role);
|
||||
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);
|
||||
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_disable(bs_top);
|
||||
}
|
||||
@ -3201,6 +3198,7 @@ void bdrv_init_with_whitelist(void)
|
||||
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BdrvChild *child;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
@ -3215,13 +3213,20 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
} else if (bs->file) {
|
||||
bdrv_invalidate_cache(bs->file->bs, &local_err);
|
||||
if (local_err) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (local_err) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_invalidate_cache(child->bs, &local_err);
|
||||
if (local_err) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (bs->drv->bdrv_inactivate) {
|
||||
if (!setting_flag && bs->drv->bdrv_inactivate) {
|
||||
ret = bs->drv->bdrv_inactivate(bs);
|
||||
if (ret < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
int bdrv_inactivate_all(void)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int pass;
|
||||
|
||||
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);
|
||||
ret = bdrv_inactivate(bs);
|
||||
aio_context_release(aio_context);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
/* We do two passes of inactivation. The first pass calls to drivers'
|
||||
* .bdrv_inactivate callbacks recursively so all cache is flushed to disk;
|
||||
* the second pass sets the BDRV_O_INACTIVE flag so that no further write
|
||||
* is allowed. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QEMU Block backends
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
* Copyright (C) 2014-2016 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>,
|
||||
@ -692,7 +692,7 @@ static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
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,
|
||||
@ -710,7 +710,7 @@ static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||
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 {
|
||||
@ -772,55 +772,28 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
return rwco.ret;
|
||||
}
|
||||
|
||||
static int blk_rw(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
|
||||
int nb_sectors, CoroutineEntry co_entry,
|
||||
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)
|
||||
int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
int count)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
bool enabled;
|
||||
int ret;
|
||||
|
||||
ret = blk_check_request(blk, sector_num, nb_sectors);
|
||||
ret = blk_check_byte_request(blk, offset, count);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
enabled = bs->io_limits_enabled;
|
||||
bs->io_limits_enabled = false;
|
||||
ret = blk_read(blk, sector_num, buf, nb_sectors);
|
||||
bs->io_limits_enabled = enabled;
|
||||
bdrv_no_throttling_begin(bs);
|
||||
ret = blk_pread(blk, offset, buf, count);
|
||||
bdrv_no_throttling_end(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
|
||||
int nb_sectors)
|
||||
int blk_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, BdrvRequestFlags flags)
|
||||
{
|
||||
return blk_rw(blk, sector_num, (uint8_t*) buf, nb_sectors,
|
||||
blk_write_entry, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
return blk_prw(blk, offset, NULL, count, blk_write_entry,
|
||||
flags | BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
static void error_callback_bh(void *opaque)
|
||||
@ -932,18 +905,12 @@ static void blk_aio_write_entry(void *opaque)
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags,
|
||||
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, 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);
|
||||
}
|
||||
|
||||
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);
|
||||
return blk_aio_prwv(blk, offset, count, NULL, blk_aio_write_entry,
|
||||
flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -991,30 +960,20 @@ int64_t blk_nb_sectors(BlockBackend *blk)
|
||||
return bdrv_nb_sectors(blk_bs(blk));
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
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,
|
||||
BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
|
||||
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);
|
||||
}
|
||||
return blk_aio_prwv(blk, offset, qiov->size, qiov,
|
||||
blk_aio_read_entry, flags, cb, opaque);
|
||||
}
|
||||
|
||||
assert(nb_sectors << BDRV_SECTOR_BITS == iov->size);
|
||||
return blk_aio_prwv(blk, sector_num << BDRV_SECTOR_BITS, iov->size, iov,
|
||||
blk_aio_write_entry, 0, cb, opaque);
|
||||
BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
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,
|
||||
@ -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);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, BdrvRequestFlags flags)
|
||||
{
|
||||
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return blk_co_pwritev(blk, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS, NULL,
|
||||
return blk_co_pwritev(blk, offset, count, NULL,
|
||||
flags | BDRV_REQ_ZERO_WRITE);
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
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;
|
||||
|
||||
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) {
|
||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||
if (block_offset < 0) {
|
||||
return block_offset;
|
||||
} else if (block_offset > 0) {
|
||||
ret = bdrv_pread(bs->file->bs, block_offset, buf, 512);
|
||||
ret = block_offset;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
memset(buf, 0, 512);
|
||||
qemu_iovec_memset(&local_qiov, 0, 0, 512);
|
||||
}
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
bytes_done += 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int bochs_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = bochs_read(bs, sector_num, buf, nb_sectors);
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -267,7 +282,7 @@ static BlockDriver bdrv_bochs = {
|
||||
.instance_size = sizeof(BDRVBochsState),
|
||||
.bdrv_probe = bochs_probe,
|
||||
.bdrv_open = bochs_open,
|
||||
.bdrv_read = bochs_co_read,
|
||||
.bdrv_co_preadv = bochs_co_preadv,
|
||||
.bdrv_close = bochs_close,
|
||||
};
|
||||
|
||||
|
@ -66,6 +66,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
bs->read_only = 1;
|
||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
||||
|
||||
/* read header */
|
||||
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;
|
||||
}
|
||||
|
||||
static int cloop_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
cloop_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
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++) {
|
||||
void *data;
|
||||
uint32_t sector_offset_in_block =
|
||||
((sector_num + i) % s->sectors_per_block),
|
||||
block_num = (sector_num + i) / s->sectors_per_block;
|
||||
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,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = cloop_read(bs, sector_num, buf, nb_sectors);
|
||||
data = s->uncompressed_block + sector_offset_in_block * 512;
|
||||
qemu_iovec_from_buf(qiov, i * 512, data, 512);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -273,7 +279,7 @@ static BlockDriver bdrv_cloop = {
|
||||
.instance_size = sizeof(BDRVCloopState),
|
||||
.bdrv_probe = cloop_probe,
|
||||
.bdrv_open = cloop_open,
|
||||
.bdrv_read = cloop_co_read,
|
||||
.bdrv_co_preadv = cloop_co_preadv,
|
||||
.bdrv_close = cloop_close,
|
||||
};
|
||||
|
||||
|
@ -91,7 +91,7 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
|
||||
struct BlockCryptoCreateData *data = opaque;
|
||||
ssize_t ret;
|
||||
|
||||
ret = blk_pwrite(data->blk, offset, buf, buflen);
|
||||
ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write encryption header");
|
||||
return ret;
|
||||
|
10
block/curl.c
10
block/curl.c
@ -36,10 +36,16 @@
|
||||
// #define DEBUG_VERBOSE
|
||||
|
||||
#ifdef DEBUG_CURL
|
||||
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
|
||||
#define DEBUG_CURL_PRINT 1
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do { } while (0)
|
||||
#define DEBUG_CURL_PRINT 0
|
||||
#endif
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_CURL_PRINT) { \
|
||||
fprintf(stderr, fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
|
40
block/dmg.c
40
block/dmg.c
@ -440,6 +440,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
bs->read_only = 1;
|
||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
||||
|
||||
s->n_chunks = 0;
|
||||
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
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++) {
|
||||
uint32_t sector_offset_in_chunk;
|
||||
void *data;
|
||||
|
||||
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
|
||||
* s->uncompressed_chunk may be too small to cover the large all-zeroes
|
||||
* section. dmg_read_chunk is called to find s->current_chunk */
|
||||
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;
|
||||
}
|
||||
sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
|
||||
memcpy(buf + i * 512,
|
||||
s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
|
||||
data = s->uncompressed_chunk + sector_offset_in_chunk * 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,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = dmg_read(bs, sector_num, buf, nb_sectors);
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
return ret;
|
||||
}
|
||||
@ -715,7 +721,7 @@ static BlockDriver bdrv_dmg = {
|
||||
.instance_size = sizeof(BDRVDMGState),
|
||||
.bdrv_probe = dmg_probe,
|
||||
.bdrv_open = dmg_open,
|
||||
.bdrv_read = dmg_co_read,
|
||||
.bdrv_co_preadv = dmg_co_preadv,
|
||||
.bdrv_close = dmg_close,
|
||||
};
|
||||
|
||||
|
514
block/io.c
514
block/io.c
@ -34,18 +34,6 @@
|
||||
|
||||
#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,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
@ -62,48 +50,35 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
void bdrv_set_io_limits(BlockDriverState *bs,
|
||||
ThrottleConfig *cfg)
|
||||
{
|
||||
int i;
|
||||
|
||||
throttle_group_config(bs, cfg);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
qemu_co_enter_next(&bs->throttled_reqs[i]);
|
||||
void bdrv_no_throttling_begin(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->io_limits_disabled++ == 0) {
|
||||
throttle_group_restart_bs(bs);
|
||||
}
|
||||
}
|
||||
|
||||
/* this function drain all the throttled IOs */
|
||||
static bool bdrv_start_throttled_reqs(BlockDriverState *bs)
|
||||
void bdrv_no_throttling_end(BlockDriverState *bs)
|
||||
{
|
||||
bool drained = false;
|
||||
bool enabled = bs->io_limits_enabled;
|
||||
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;
|
||||
assert(bs->io_limits_disabled);
|
||||
--bs->io_limits_disabled;
|
||||
}
|
||||
|
||||
void bdrv_io_limits_disable(BlockDriverState *bs)
|
||||
{
|
||||
bs->io_limits_enabled = false;
|
||||
bdrv_start_throttled_reqs(bs);
|
||||
assert(bs->throttle_state);
|
||||
bdrv_no_throttling_begin(bs);
|
||||
throttle_group_unregister_bs(bs);
|
||||
bdrv_no_throttling_end(bs);
|
||||
}
|
||||
|
||||
/* should be called before bdrv_set_io_limits if a limit is set */
|
||||
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);
|
||||
bs->io_limits_enabled = true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
@ -260,18 +217,29 @@ typedef struct {
|
||||
bool done;
|
||||
} 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)
|
||||
{
|
||||
BdrvCoDrainData *data = opaque;
|
||||
Coroutine *co = data->co;
|
||||
|
||||
qemu_bh_delete(data->bh);
|
||||
bdrv_drain(data->bs);
|
||||
bdrv_drain_poll(data->bs);
|
||||
data->done = true;
|
||||
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;
|
||||
|
||||
@ -305,21 +273,28 @@ void coroutine_fn bdrv_co_drain(BlockDriverState *bs)
|
||||
* not depend on events in other AioContexts. In that case, use
|
||||
* 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)
|
||||
{
|
||||
bool busy = true;
|
||||
|
||||
bdrv_no_throttling_begin(bs);
|
||||
bdrv_io_unplugged_begin(bs);
|
||||
bdrv_drain_recurse(bs);
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_drain(bs);
|
||||
return;
|
||||
}
|
||||
while (busy) {
|
||||
/* Keep iterating */
|
||||
bdrv_flush_io_queue(bs);
|
||||
busy = bdrv_requests_pending(bs);
|
||||
busy |= aio_poll(bdrv_get_aio_context(bs), busy);
|
||||
bdrv_co_yield_to_drain(bs);
|
||||
} else {
|
||||
bdrv_drain_poll(bs);
|
||||
}
|
||||
bdrv_io_unplugged_end(bs);
|
||||
bdrv_no_throttling_end(bs);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -342,6 +317,8 @@ void bdrv_drain_all(void)
|
||||
if (bs->job) {
|
||||
block_job_pause(bs->job);
|
||||
}
|
||||
bdrv_no_throttling_begin(bs);
|
||||
bdrv_io_unplugged_begin(bs);
|
||||
bdrv_drain_recurse(bs);
|
||||
aio_context_release(aio_context);
|
||||
|
||||
@ -366,7 +343,6 @@ void bdrv_drain_all(void)
|
||||
aio_context_acquire(aio_context);
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
if (aio_context == bdrv_get_aio_context(bs)) {
|
||||
bdrv_flush_io_queue(bs);
|
||||
if (bdrv_requests_pending(bs)) {
|
||||
busy = true;
|
||||
aio_poll(aio_context, busy);
|
||||
@ -383,6 +359,8 @@ void bdrv_drain_all(void)
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_io_unplugged_end(bs);
|
||||
bdrv_no_throttling_end(bs);
|
||||
if (bs->job) {
|
||||
block_job_resume(bs->job);
|
||||
}
|
||||
@ -581,13 +559,13 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
|
||||
RwCo *rwco = opaque;
|
||||
|
||||
if (!rwco->is_write) {
|
||||
rwco->ret = bdrv_co_do_preadv(rwco->bs, rwco->offset,
|
||||
rwco->qiov->size, rwco->qiov,
|
||||
rwco->flags);
|
||||
rwco->ret = bdrv_co_preadv(rwco->bs, rwco->offset,
|
||||
rwco->qiov->size, rwco->qiov,
|
||||
rwco->flags);
|
||||
} else {
|
||||
rwco->ret = bdrv_co_do_pwritev(rwco->bs, rwco->offset,
|
||||
rwco->qiov->size, rwco->qiov,
|
||||
rwco->flags);
|
||||
rwco->ret = bdrv_co_pwritev(rwco->bs, rwco->offset,
|
||||
rwco->qiov->size, rwco->qiov,
|
||||
rwco->flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,17 +586,6 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset,
|
||||
.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()) {
|
||||
/* Fast-path if already in coroutine context */
|
||||
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.
|
||||
* 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
|
||||
* 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().
|
||||
*/
|
||||
@ -800,6 +768,109 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
||||
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,
|
||||
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);
|
||||
|
||||
ret = drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
|
||||
&bounce_qiov);
|
||||
ret = bdrv_driver_preadv(bs, cluster_sector_num * BDRV_SECTOR_SIZE,
|
||||
cluster_nb_sectors * BDRV_SECTOR_SIZE,
|
||||
&bounce_qiov, 0);
|
||||
if (ret < 0) {
|
||||
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
|
||||
* to flush even in cache=writethrough mode.
|
||||
*/
|
||||
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
|
||||
&bounce_qiov);
|
||||
ret = bdrv_driver_pwritev(bs, cluster_sector_num * BDRV_SECTOR_SIZE,
|
||||
cluster_nb_sectors * BDRV_SECTOR_SIZE,
|
||||
&bounce_qiov, 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,
|
||||
int64_t align, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
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 */
|
||||
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 {
|
||||
/* Read zeros after EOF */
|
||||
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),
|
||||
align >> BDRV_SECTOR_BITS);
|
||||
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) {
|
||||
QEMUIOVector local_qiov;
|
||||
|
||||
@ -943,8 +1015,9 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
||||
qemu_iovec_concat(&local_qiov, qiov, 0,
|
||||
max_nb_sectors * BDRV_SECTOR_SIZE);
|
||||
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, max_nb_sectors,
|
||||
&local_qiov);
|
||||
ret = bdrv_driver_preadv(bs, offset,
|
||||
max_nb_sectors * BDRV_SECTOR_SIZE,
|
||||
&local_qiov, 0);
|
||||
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
} else {
|
||||
@ -967,7 +1040,7 @@ out:
|
||||
/*
|
||||
* 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,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@ -997,7 +1070,7 @@ int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* throttling disk I/O */
|
||||
if (bs->io_limits_enabled) {
|
||||
if (bs->throttle_state) {
|
||||
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 bdrv_co_do_preadv(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||
return bdrv_co_preadv(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||
}
|
||||
|
||||
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;
|
||||
struct iovec iov = {0};
|
||||
int ret = 0;
|
||||
bool need_flush = false;
|
||||
|
||||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_write_zeroes,
|
||||
BDRV_REQUEST_MAX_SECTORS);
|
||||
@ -1120,13 +1194,29 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
ret = -ENOTSUP;
|
||||
/* First try the efficient write zeroes operation */
|
||||
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) {
|
||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||
int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length,
|
||||
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);
|
||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||
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);
|
||||
|
||||
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
|
||||
* all future requests.
|
||||
@ -1155,6 +1247,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
fail:
|
||||
if (ret == 0 && need_flush) {
|
||||
ret = bdrv_co_flush(bs);
|
||||
}
|
||||
qemu_vfree(iov.iov_base);
|
||||
return ret;
|
||||
}
|
||||
@ -1199,23 +1294,12 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
|
||||
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 {
|
||||
assert(drv->supported_write_flags == 0);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (bs->wr_highest_offset < offset + bytes) {
|
||||
@ -1320,7 +1404,7 @@ fail:
|
||||
/*
|
||||
* 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,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@ -1347,7 +1431,7 @@ int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* throttling disk I/O */
|
||||
if (bs->io_limits_enabled) {
|
||||
if (bs->throttle_state) {
|
||||
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 bdrv_co_do_pwritev(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||
return bdrv_co_pwritev(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
nb_sectors << BDRV_SECTOR_BITS, qiov, flags);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
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 {
|
||||
BlockAIOCB common;
|
||||
BlockRequest req;
|
||||
@ -2314,59 +2324,6 @@ void qemu_aio_unref(void *p)
|
||||
/**************************************************************/
|
||||
/* 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)
|
||||
{
|
||||
RwCo *rwco = opaque;
|
||||
@ -2763,33 +2720,68 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
|
||||
|
||||
void bdrv_io_plug(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (drv && drv->bdrv_io_plug) {
|
||||
drv->bdrv_io_plug(bs);
|
||||
} else if (bs->file) {
|
||||
bdrv_io_plug(bs->file->bs);
|
||||
BdrvChild *child;
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_io_plug(child->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)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (drv && drv->bdrv_io_unplug) {
|
||||
drv->bdrv_io_unplug(bs);
|
||||
} else if (bs->file) {
|
||||
bdrv_io_unplug(bs->file->bs);
|
||||
BdrvChild *child;
|
||||
|
||||
assert(bs->io_plugged);
|
||||
if (--bs->io_plugged == 0 && bs->io_plug_disabled == 0) {
|
||||
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;
|
||||
if (drv && drv->bdrv_flush_io_queue) {
|
||||
drv->bdrv_flush_io_queue(bs);
|
||||
} else if (bs->file) {
|
||||
bdrv_flush_io_queue(bs->file->bs);
|
||||
BdrvChild *child;
|
||||
|
||||
if (bs->io_plug_disabled++ == 0 && bs->io_plugged > 0) {
|
||||
BlockDriver *drv = bs->drv;
|
||||
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)
|
||||
|
@ -456,8 +456,11 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
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)) {
|
||||
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);
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
fua = iscsilun->dpofua && (flags & BDRV_REQ_FUA);
|
||||
if (iscsilun->use_16_for_rw) {
|
||||
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
@ -513,13 +515,6 @@ retry:
|
||||
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,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
@ -1555,6 +1550,10 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
task = NULL;
|
||||
|
||||
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 */
|
||||
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_write_zeroes = iscsi_co_write_zeroes,
|
||||
.bdrv_co_readv = iscsi_co_readv,
|
||||
.bdrv_co_writev = iscsi_co_writev,
|
||||
.bdrv_co_writev_flags = iscsi_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_flush_to_disk = iscsi_co_flush,
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
struct qemu_laiocb {
|
||||
BlockAIOCB common;
|
||||
struct qemu_laio_state *ctx;
|
||||
LinuxAioState *ctx;
|
||||
struct iocb iocb;
|
||||
ssize_t ret;
|
||||
size_t nbytes;
|
||||
@ -46,7 +46,7 @@ typedef struct {
|
||||
QSIMPLEQ_HEAD(, qemu_laiocb) pending;
|
||||
} LaioQueue;
|
||||
|
||||
struct qemu_laio_state {
|
||||
struct LinuxAioState {
|
||||
io_context_t ctx;
|
||||
EventNotifier e;
|
||||
|
||||
@ -60,7 +60,7 @@ struct qemu_laio_state {
|
||||
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)
|
||||
{
|
||||
@ -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).
|
||||
*/
|
||||
static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
||||
struct qemu_laiocb *laiocb)
|
||||
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
||||
{
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
@ -107,7 +106,7 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
||||
*/
|
||||
static void qemu_laio_completion_bh(void *opaque)
|
||||
{
|
||||
struct qemu_laio_state *s = opaque;
|
||||
LinuxAioState *s = opaque;
|
||||
|
||||
/* Fetch more completion events when empty */
|
||||
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]);
|
||||
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)) {
|
||||
@ -146,7 +145,7 @@ static void qemu_laio_completion_bh(void *opaque)
|
||||
|
||||
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)) {
|
||||
qemu_bh_schedule(s->completion_bh);
|
||||
@ -185,7 +184,7 @@ static void ioq_init(LaioQueue *io_q)
|
||||
io_q->blocked = false;
|
||||
}
|
||||
|
||||
static void ioq_submit(struct qemu_laio_state *s)
|
||||
static void ioq_submit(LinuxAioState *s)
|
||||
{
|
||||
int ret, len;
|
||||
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);
|
||||
}
|
||||
|
||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
||||
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
|
||||
{
|
||||
struct qemu_laio_state *s = aio_ctx;
|
||||
|
||||
s->io_q.plugged++;
|
||||
assert(!s->io_q.plugged);
|
||||
s->io_q.plugged = 1;
|
||||
}
|
||||
|
||||
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 > 0 || !unplug);
|
||||
|
||||
if (unplug && --s->io_q.plugged > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(s->io_q.plugged);
|
||||
s->io_q.plugged = 0;
|
||||
if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
|
||||
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,
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
struct qemu_laio_state *s = aio_ctx;
|
||||
struct qemu_laiocb *laiocb;
|
||||
struct iocb *iocbs;
|
||||
off_t offset = sector_num * 512;
|
||||
@ -284,26 +275,22 @@ out_free_aiocb:
|
||||
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);
|
||||
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);
|
||||
aio_set_event_notifier(new_context, &s->e, false,
|
||||
qemu_laio_completion_cb);
|
||||
}
|
||||
|
||||
void *laio_init(void)
|
||||
LinuxAioState *laio_init(void)
|
||||
{
|
||||
struct qemu_laio_state *s;
|
||||
LinuxAioState *s;
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
if (event_notifier_init(&s->e, false) < 0) {
|
||||
@ -325,10 +312,8 @@ out_free_state:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void laio_cleanup(void *s_)
|
||||
void laio_cleanup(LinuxAioState *s)
|
||||
{
|
||||
struct qemu_laio_state *s = s_;
|
||||
|
||||
event_notifier_cleanup(&s->e);
|
||||
|
||||
if (io_destroy(s->ctx) != 0) {
|
||||
|
@ -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,
|
||||
int nb_sectors, QEMUIOVector *qiov,
|
||||
int offset, int *flags)
|
||||
int offset, int flags)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = { .type = NBD_CMD_WRITE };
|
||||
struct nbd_reply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if ((*flags & BDRV_REQ_FUA) && (client->nbdflags & NBD_FLAG_SEND_FUA)) {
|
||||
*flags &= ~BDRV_REQ_FUA;
|
||||
if (flags & BDRV_REQ_FUA) {
|
||||
assert(client->nbdflags & NBD_FLAG_SEND_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 nb_sectors, QEMUIOVector *qiov, int *flags)
|
||||
int nb_sectors, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int offset = 0;
|
||||
int ret;
|
||||
@ -414,6 +414,9 @@ int nbd_client_init(BlockDriverState *bs,
|
||||
logout("Failed to negotiate with the NBD server\n");
|
||||
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->free_sema);
|
||||
|
@ -48,7 +48,7 @@ int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors);
|
||||
int nbd_client_co_flush(BlockDriverState *bs);
|
||||
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 nb_sectors, QEMUIOVector *qiov);
|
||||
|
||||
|
37
block/nbd.c
37
block/nbd.c
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return nbd_client_co_flush(bs);
|
||||
@ -476,9 +451,7 @@ static BlockDriver bdrv_nbd = {
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_writev_flags = nbd_client_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
@ -496,9 +469,7 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_writev_flags = nbd_client_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
@ -516,9 +487,7 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.bdrv_parse_filename = nbd_parse_filename,
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_readv = nbd_co_readv,
|
||||
.bdrv_co_writev = nbd_co_writev,
|
||||
.bdrv_co_writev_flags = nbd_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_writev_flags = nbd_client_co_writev,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_discard = nbd_co_discard,
|
||||
|
@ -512,11 +512,12 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
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) {
|
||||
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) {
|
||||
goto exit;
|
||||
}
|
||||
|
@ -853,14 +853,14 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (backing_file) {
|
||||
ret = blk_pwrite(qcow_blk, sizeof(header),
|
||||
backing_file, backing_filename_len);
|
||||
backing_file, backing_filename_len, 0);
|
||||
if (ret != backing_filename_len) {
|
||||
goto exit;
|
||||
}
|
||||
@ -869,8 +869,8 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
tmp = g_malloc0(BDRV_SECTOR_SIZE);
|
||||
for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
|
||||
BDRV_SECTOR_SIZE); i++) {
|
||||
ret = blk_pwrite(qcow_blk, header_size +
|
||||
BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE);
|
||||
ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
|
||||
tmp, BDRV_SECTOR_SIZE, 0);
|
||||
if (ret != BDRV_SECTOR_SIZE) {
|
||||
g_free(tmp);
|
||||
goto exit;
|
||||
|
@ -1757,13 +1757,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
||||
ret = blk_pwrite(blk, 0, header, cluster_size);
|
||||
ret = blk_pwrite(blk, 0, header, cluster_size, 0);
|
||||
g_free(header);
|
||||
if (ret < 0) {
|
||||
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 */
|
||||
refcount_table = g_malloc0(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);
|
||||
|
||||
if (ret < 0) {
|
||||
@ -2411,21 +2404,74 @@ finish:
|
||||
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,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
|
||||
/* Emulate misaligned zero writes */
|
||||
if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) {
|
||||
return -ENOTSUP;
|
||||
int head = sector_num % s->cluster_sectors;
|
||||
int tail = (sector_num + nb_sectors) % s->cluster_sectors;
|
||||
|
||||
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 */
|
||||
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);
|
||||
|
||||
return ret;
|
||||
|
12
block/qed.c
12
block/qed.c
@ -601,18 +601,18 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
}
|
||||
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
ret = blk_pwrite(blk, sizeof(le_header), backing_file,
|
||||
header.backing_filename_size);
|
||||
header.backing_filename_size, 0);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
@ -1594,12 +1594,6 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
|
||||
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));
|
||||
ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
|
||||
if (local_err) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
@ -67,6 +68,9 @@ typedef struct QuorumVotes {
|
||||
typedef struct BDRVQuorumState {
|
||||
BdrvChild **children; /* children BlockDriverStates */
|
||||
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
|
||||
* same result a quorum error occurs.
|
||||
*/
|
||||
@ -747,21 +751,6 @@ static int64_t quorum_getlength(BlockDriverState *bs)
|
||||
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)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
@ -898,9 +887,9 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
if (s->num_children < 2) {
|
||||
if (s->num_children < 1) {
|
||||
error_setg(&local_err,
|
||||
"Number of provided children must be greater than 1");
|
||||
"Number of provided children must be 1 or more");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
@ -964,6 +953,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
opened[i] = true;
|
||||
}
|
||||
s->next_child_index = s->num_children;
|
||||
|
||||
g_free(opened);
|
||||
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)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
@ -1070,11 +1126,13 @@ static BlockDriver bdrv_quorum = {
|
||||
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_invalidate_cache = quorum_invalidate_cache,
|
||||
|
||||
.bdrv_detach_aio_context = quorum_detach_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,
|
||||
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
|
||||
};
|
||||
|
@ -35,15 +35,16 @@
|
||||
|
||||
/* linux-aio.c - Linux native implementation */
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
void *laio_init(void);
|
||||
void laio_cleanup(void *s);
|
||||
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
typedef struct LinuxAioState LinuxAioState;
|
||||
LinuxAioState *laio_init(void);
|
||||
void laio_cleanup(LinuxAioState *s);
|
||||
BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque, int type);
|
||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
||||
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
||||
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
|
||||
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
|
||||
void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -139,7 +139,7 @@ typedef struct BDRVRawState {
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
int use_aio;
|
||||
void *aio_ctx;
|
||||
LinuxAioState *aio_ctx;
|
||||
#endif
|
||||
#ifdef CONFIG_XFS
|
||||
bool is_xfs:1;
|
||||
@ -398,7 +398,7 @@ static void raw_attach_aio_context(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
#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;
|
||||
assert(aio_ctx != NULL);
|
||||
@ -517,6 +517,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
@ -1345,17 +1346,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->use_aio) {
|
||||
laio_io_unplug(bs, s->aio_ctx, true);
|
||||
}
|
||||
#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);
|
||||
laio_io_unplug(bs, s->aio_ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1949,7 +1940,6 @@ BlockDriver bdrv_file = {
|
||||
.bdrv_refresh_limits = raw_refresh_limits,
|
||||
.bdrv_io_plug = raw_aio_plug,
|
||||
.bdrv_io_unplug = raw_aio_unplug,
|
||||
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
@ -2398,7 +2388,6 @@ static BlockDriver bdrv_host_device = {
|
||||
.bdrv_refresh_limits = raw_refresh_limits,
|
||||
.bdrv_io_plug = raw_aio_plug,
|
||||
.bdrv_io_unplug = raw_aio_unplug,
|
||||
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
@ -2528,7 +2517,6 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_refresh_limits = raw_refresh_limits,
|
||||
.bdrv_io_plug = raw_aio_plug,
|
||||
.bdrv_io_unplug = raw_aio_unplug,
|
||||
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
@ -2664,7 +2652,6 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
.bdrv_refresh_limits = raw_refresh_limits,
|
||||
.bdrv_io_plug = raw_aio_plug,
|
||||
.bdrv_io_unplug = raw_aio_unplug,
|
||||
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
|
@ -105,8 +105,8 @@ raw_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
|
||||
}
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
||||
ret = bdrv_co_do_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
|
||||
ret = bdrv_co_pwritev(bs->file->bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, qiov, flags);
|
||||
|
||||
fail:
|
||||
if (qiov == &local_qiov) {
|
||||
@ -116,13 +116,6 @@ fail:
|
||||
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,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum,
|
||||
@ -211,6 +204,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
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)) {
|
||||
fprintf(stderr,
|
||||
@ -256,9 +251,7 @@ BlockDriver bdrv_raw = {
|
||||
.bdrv_close = &raw_close,
|
||||
.bdrv_create = &raw_create,
|
||||
.bdrv_co_readv = &raw_co_readv,
|
||||
.bdrv_co_writev = &raw_co_writev,
|
||||
.bdrv_co_writev_flags = &raw_co_writev_flags,
|
||||
.supported_write_flags = BDRV_REQ_FUA,
|
||||
.bdrv_co_write_zeroes = &raw_co_write_zeroes,
|
||||
.bdrv_co_discard = &raw_co_discard,
|
||||
.bdrv_co_get_block_status = &raw_co_get_block_status,
|
||||
|
@ -294,13 +294,16 @@ static inline size_t count_data_objs(const struct SheepdogInode *inode)
|
||||
|
||||
#undef DPRINTF
|
||||
#ifdef DEBUG_SDOG
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
fprintf(stdout, "%s %d: " fmt, __func__, __LINE__, ##args); \
|
||||
} while (0)
|
||||
#define DEBUG_SDOG_PRINT 1
|
||||
#else
|
||||
#define DPRINTF(fmt, args...)
|
||||
#define DEBUG_SDOG_PRINT 0
|
||||
#endif
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
if (DEBUG_SDOG_PRINT) { \
|
||||
fprintf(stderr, "%s %d: " fmt, __func__, __LINE__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct SheepdogAIOCB SheepdogAIOCB;
|
||||
|
||||
@ -1678,7 +1681,7 @@ static int sd_prealloc(const char *filename, Error **errp)
|
||||
if (ret < 0) {
|
||||
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) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -219,6 +219,10 @@ static bool throttle_group_schedule_timer(BlockDriverState *bs,
|
||||
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
|
||||
bool must_wait;
|
||||
|
||||
if (bs->io_limits_disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if any of the timers in this group is already armed */
|
||||
if (tg->any_timer_armed[is_write]) {
|
||||
return true;
|
||||
@ -313,6 +317,17 @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs,
|
||||
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
|
||||
* to throttle_config(), but guarantees atomicity within the
|
||||
* throttling group.
|
||||
@ -335,6 +350,9 @@ void throttle_group_config(BlockDriverState *bs, ThrottleConfig *cfg)
|
||||
}
|
||||
throttle_config(ts, tt, cfg);
|
||||
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
|
||||
|
133
block/vdi.c
133
block/vdi.c
@ -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;
|
||||
}
|
||||
|
||||
static int vdi_co_read(BlockDriverState *bs,
|
||||
int64_t sector_num, uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
QEMUIOVector local_qiov;
|
||||
uint32_t bmap_entry;
|
||||
uint32_t block_index;
|
||||
uint32_t sector_in_block;
|
||||
uint32_t n_sectors;
|
||||
uint32_t offset_in_block;
|
||||
uint32_t n_bytes;
|
||||
uint64_t bytes_done = 0;
|
||||
int ret = 0;
|
||||
|
||||
logout("\n");
|
||||
|
||||
while (ret >= 0 && nb_sectors > 0) {
|
||||
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;
|
||||
}
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
|
||||
logout("will read %u sectors starting at sector %" PRIu64 "\n",
|
||||
n_sectors, sector_num);
|
||||
while (ret >= 0 && bytes > 0) {
|
||||
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 */
|
||||
bmap_entry = le32_to_cpu(s->bmap[block_index]);
|
||||
if (!VDI_IS_ALLOCATED(bmap_entry)) {
|
||||
/* 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;
|
||||
} else {
|
||||
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
|
||||
(uint64_t)bmap_entry * s->block_sectors +
|
||||
sector_in_block;
|
||||
ret = bdrv_read(bs->file->bs, offset, buf, n_sectors);
|
||||
}
|
||||
logout("%u sectors read\n", n_sectors);
|
||||
uint64_t data_offset = s->header.offset_data +
|
||||
(uint64_t)bmap_entry * s->block_size +
|
||||
offset_in_block;
|
||||
|
||||
nb_sectors -= n_sectors;
|
||||
sector_num += n_sectors;
|
||||
buf += n_sectors * SECTOR_SIZE;
|
||||
qemu_iovec_reset(&local_qiov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int vdi_co_write(BlockDriverState *bs,
|
||||
int64_t sector_num, const uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVdiState *s = bs->opaque;
|
||||
QEMUIOVector local_qiov;
|
||||
uint32_t bmap_entry;
|
||||
uint32_t block_index;
|
||||
uint32_t sector_in_block;
|
||||
uint32_t n_sectors;
|
||||
uint32_t offset_in_block;
|
||||
uint32_t n_bytes;
|
||||
uint32_t bmap_first = VDI_UNALLOCATED;
|
||||
uint32_t bmap_last = VDI_UNALLOCATED;
|
||||
uint8_t *block = NULL;
|
||||
uint64_t bytes_done = 0;
|
||||
int ret = 0;
|
||||
|
||||
logout("\n");
|
||||
|
||||
while (ret >= 0 && nb_sectors > 0) {
|
||||
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;
|
||||
}
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
|
||||
logout("will write %u sectors starting at sector %" PRIu64 "\n",
|
||||
n_sectors, sector_num);
|
||||
while (ret >= 0 && bytes > 0) {
|
||||
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 */
|
||||
bmap_entry = le32_to_cpu(s->bmap[block_index]);
|
||||
if (!VDI_IS_ALLOCATED(bmap_entry)) {
|
||||
/* Allocate new block and write to it. */
|
||||
uint64_t offset;
|
||||
uint64_t data_offset;
|
||||
bmap_entry = s->header.blocks_allocated;
|
||||
s->bmap[block_index] = cpu_to_le32(bmap_entry);
|
||||
s->header.blocks_allocated++;
|
||||
offset = s->header.offset_data / SECTOR_SIZE +
|
||||
(uint64_t)bmap_entry * s->block_sectors;
|
||||
data_offset = s->header.offset_data +
|
||||
(uint64_t)bmap_entry * s->block_size;
|
||||
if (block == NULL) {
|
||||
block = g_malloc(s->block_size);
|
||||
bmap_first = block_index;
|
||||
}
|
||||
bmap_last = block_index;
|
||||
/* Copy data to be written to new block and zero unused parts. */
|
||||
memset(block, 0, sector_in_block * SECTOR_SIZE);
|
||||
memcpy(block + sector_in_block * SECTOR_SIZE,
|
||||
buf, n_sectors * SECTOR_SIZE);
|
||||
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
|
||||
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
|
||||
memset(block, 0, offset_in_block);
|
||||
qemu_iovec_to_buf(qiov, bytes_done, block + offset_in_block,
|
||||
n_bytes);
|
||||
memset(block + offset_in_block + n_bytes, 0,
|
||||
s->block_size - n_bytes - offset_in_block);
|
||||
|
||||
/* Note that this coroutine does not yield anywhere from reading the
|
||||
* 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
|
||||
* the other coroutines can write to the affected area. */
|
||||
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);
|
||||
} else {
|
||||
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
|
||||
(uint64_t)bmap_entry * s->block_sectors +
|
||||
sector_in_block;
|
||||
uint64_t data_offset = s->header.offset_data +
|
||||
(uint64_t)bmap_entry * s->block_size +
|
||||
offset_in_block;
|
||||
qemu_co_mutex_lock(&s->write_lock);
|
||||
/* This lock is only used to make sure the following write operation
|
||||
* 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
|
||||
* in flight, but they do not concern this very operation). */
|
||||
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;
|
||||
sector_num += n_sectors;
|
||||
buf += n_sectors * SECTOR_SIZE;
|
||||
bytes -= n_bytes;
|
||||
offset += n_bytes;
|
||||
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");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -694,6 +712,7 @@ static int vdi_co_write(BlockDriverState *bs,
|
||||
VdiHeader *header = (VdiHeader *) block;
|
||||
uint8_t *base;
|
||||
uint64_t offset;
|
||||
uint32_t n_sectors;
|
||||
|
||||
logout("now writing modified header\n");
|
||||
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);
|
||||
#endif
|
||||
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) {
|
||||
error_setg(errp, "Error writing header to %s", filename);
|
||||
goto exit;
|
||||
@ -829,7 +848,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
bmap[i] = VDI_UNALLOCATED;
|
||||
}
|
||||
}
|
||||
ret = blk_pwrite(blk, offset, bmap, bmap_size);
|
||||
ret = blk_pwrite(blk, offset, bmap, bmap_size, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Error writing bmap to %s", filename);
|
||||
goto exit;
|
||||
@ -903,9 +922,9 @@ static BlockDriver bdrv_vdi = {
|
||||
.bdrv_co_get_block_status = vdi_co_get_block_status,
|
||||
.bdrv_make_empty = vdi_make_empty,
|
||||
|
||||
.bdrv_read = vdi_co_read,
|
||||
.bdrv_co_preadv = vdi_co_preadv,
|
||||
#if defined(CONFIG_VDI_WRITE)
|
||||
.bdrv_write = vdi_co_write,
|
||||
.bdrv_co_pwritev = vdi_co_pwritev,
|
||||
#endif
|
||||
|
||||
.bdrv_get_info = vdi_get_info,
|
||||
|
@ -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_items, NULL);
|
||||
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) {
|
||||
goto delete_and_exit;
|
||||
}
|
||||
if (creator) {
|
||||
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
|
||||
creator, creator_items * sizeof(gunichar2));
|
||||
creator, creator_items * sizeof(gunichar2), 0);
|
||||
if (ret < 0) {
|
||||
goto delete_and_exit;
|
||||
}
|
||||
|
373
block/vmdk.c
373
block/vmdk.c
@ -1016,27 +1016,26 @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
*/
|
||||
static int get_whole_cluster(BlockDriverState *bs,
|
||||
VmdkExtent *extent,
|
||||
uint64_t cluster_sector_num,
|
||||
uint64_t sector_num,
|
||||
uint64_t skip_start_sector,
|
||||
uint64_t skip_end_sector)
|
||||
uint64_t cluster_offset,
|
||||
uint64_t offset,
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes)
|
||||
{
|
||||
int ret = VMDK_OK;
|
||||
int64_t cluster_bytes;
|
||||
uint8_t *whole_grain;
|
||||
|
||||
/* 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;
|
||||
offset = QEMU_ALIGN_DOWN(offset, cluster_bytes);
|
||||
whole_grain = qemu_blockalign(bs, cluster_bytes);
|
||||
|
||||
if (!bs->backing) {
|
||||
memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS);
|
||||
memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0,
|
||||
cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS));
|
||||
memset(whole_grain, 0, skip_start_bytes);
|
||||
memset(whole_grain + skip_end_bytes, 0, cluster_bytes - skip_end_bytes);
|
||||
}
|
||||
|
||||
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).
|
||||
* try to read from parent image, if exist */
|
||||
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 */
|
||||
if (skip_start_sector > 0) {
|
||||
if (skip_start_bytes > 0) {
|
||||
if (bs->backing) {
|
||||
ret = bdrv_read(bs->backing->bs, sector_num,
|
||||
whole_grain, skip_start_sector);
|
||||
ret = bdrv_pread(bs->backing->bs, offset, whole_grain,
|
||||
skip_start_bytes);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
ret = bdrv_write(extent->file->bs, cluster_sector_num, whole_grain,
|
||||
skip_start_sector);
|
||||
ret = bdrv_pwrite(extent->file->bs, cluster_offset, whole_grain,
|
||||
skip_start_bytes);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* Read backing data after skip range */
|
||||
if (skip_end_sector < extent->cluster_sectors) {
|
||||
if (skip_end_bytes < cluster_bytes) {
|
||||
if (bs->backing) {
|
||||
ret = bdrv_read(bs->backing->bs, sector_num + skip_end_sector,
|
||||
whole_grain + (skip_end_sector << BDRV_SECTOR_BITS),
|
||||
extent->cluster_sectors - skip_end_sector);
|
||||
ret = bdrv_pread(bs->backing->bs, offset + skip_end_bytes,
|
||||
whole_grain + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
ret = bdrv_write(extent->file->bs, cluster_sector_num + skip_end_sector,
|
||||
whole_grain + (skip_end_sector << BDRV_SECTOR_BITS),
|
||||
extent->cluster_sectors - skip_end_sector);
|
||||
ret = bdrv_pwrite(extent->file->bs, cluster_offset + skip_end_bytes,
|
||||
whole_grain + skip_end_bytes,
|
||||
cluster_bytes - skip_end_bytes);
|
||||
if (ret < 0) {
|
||||
ret = VMDK_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = VMDK_OK;
|
||||
exit:
|
||||
qemu_vfree(whole_grain);
|
||||
return ret;
|
||||
@ -1142,8 +1142,8 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
bool allocate,
|
||||
uint64_t *cluster_offset,
|
||||
uint64_t skip_start_sector,
|
||||
uint64_t skip_end_sector)
|
||||
uint64_t skip_start_bytes,
|
||||
uint64_t skip_end_bytes)
|
||||
{
|
||||
unsigned int l1_index, l2_offset, l2_index;
|
||||
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
|
||||
* or inappropriate VM shutdown.
|
||||
*/
|
||||
ret = get_whole_cluster(bs, extent,
|
||||
cluster_sector,
|
||||
offset >> BDRV_SECTOR_BITS,
|
||||
skip_start_sector, skip_end_sector);
|
||||
ret = get_whole_cluster(bs, extent, cluster_sector * BDRV_SECTOR_SIZE,
|
||||
offset, skip_start_bytes, skip_end_bytes);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -1259,15 +1257,26 @@ static VmdkExtent *find_extent(BDRVVmdkState *s,
|
||||
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,
|
||||
int64_t sector_num)
|
||||
{
|
||||
uint64_t index_in_cluster, extent_begin_sector, extent_relative_sector_num;
|
||||
|
||||
extent_begin_sector = extent->end_sector - extent->sectors;
|
||||
extent_relative_sector_num = sector_num - extent_begin_sector;
|
||||
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
|
||||
return index_in_cluster;
|
||||
uint64_t offset;
|
||||
offset = vmdk_find_offset_in_cluster(extent, sector_num * BDRV_SECTOR_SIZE);
|
||||
return offset / BDRV_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
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,
|
||||
int64_t offset_in_cluster, const uint8_t *buf,
|
||||
int nb_sectors, int64_t sector_num)
|
||||
int64_t offset_in_cluster, QEMUIOVector *qiov,
|
||||
uint64_t qiov_offset, uint64_t n_bytes,
|
||||
uint64_t offset)
|
||||
{
|
||||
int ret;
|
||||
VmdkGrainMarker *data = NULL;
|
||||
uLongf buf_len;
|
||||
const uint8_t *write_buf = buf;
|
||||
int write_len = nb_sectors * 512;
|
||||
QEMUIOVector local_qiov;
|
||||
struct iovec iov;
|
||||
int64_t write_offset;
|
||||
int64_t write_end_sector;
|
||||
|
||||
if (extent->compressed) {
|
||||
void *compressed_data;
|
||||
|
||||
if (!extent->has_marker) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
buf_len = (extent->cluster_sectors << 9) * 2;
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (ret != write_len) {
|
||||
ret = ret < 0 ? ret : -EIO;
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
g_free(data);
|
||||
if (!extent->compressed) {
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
int64_t offset_in_cluster, uint8_t *buf,
|
||||
int nb_sectors)
|
||||
int64_t offset_in_cluster, QEMUIOVector *qiov,
|
||||
int bytes)
|
||||
{
|
||||
int ret;
|
||||
int cluster_bytes, buf_bytes;
|
||||
@ -1383,14 +1413,13 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
|
||||
|
||||
if (!extent->compressed) {
|
||||
ret = bdrv_pread(extent->file->bs,
|
||||
cluster_offset + offset_in_cluster,
|
||||
buf, nb_sectors * 512);
|
||||
if (ret == nb_sectors * 512) {
|
||||
return 0;
|
||||
} else {
|
||||
return -EIO;
|
||||
ret = bdrv_co_preadv(extent->file->bs,
|
||||
cluster_offset + offset_in_cluster, bytes,
|
||||
qiov, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
cluster_bytes = extent->cluster_sectors * 512;
|
||||
/* 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 ||
|
||||
offset_in_cluster + nb_sectors * 512 > buf_len) {
|
||||
offset_in_cluster + bytes > buf_len) {
|
||||
ret = -EINVAL;
|
||||
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;
|
||||
|
||||
out:
|
||||
@ -1435,64 +1464,73 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
int ret;
|
||||
uint64_t n, index_in_cluster;
|
||||
uint64_t n_bytes, offset_in_cluster;
|
||||
VmdkExtent *extent = NULL;
|
||||
QEMUIOVector local_qiov;
|
||||
uint64_t cluster_offset;
|
||||
uint64_t bytes_done = 0;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
extent = find_extent(s, sector_num, extent);
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
|
||||
while (bytes > 0) {
|
||||
extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent);
|
||||
if (!extent) {
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
ret = get_cluster_offset(bs, extent, NULL,
|
||||
sector_num << 9, false, &cluster_offset,
|
||||
0, 0);
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
}
|
||||
offset, false, &cluster_offset, 0, 0);
|
||||
offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
|
||||
|
||||
n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
|
||||
- offset_in_cluster);
|
||||
|
||||
if (ret != VMDK_OK) {
|
||||
/* if not allocated, try to read from parent image, if exist */
|
||||
if (bs->backing && ret != VMDK_ZEROED) {
|
||||
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) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
memset(buf, 0, 512 * n);
|
||||
qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
|
||||
}
|
||||
} else {
|
||||
ret = vmdk_read_extent(extent,
|
||||
cluster_offset, index_in_cluster * 512,
|
||||
buf, n);
|
||||
qemu_iovec_reset(&local_qiov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||
|
||||
ret = vmdk_read_extent(extent, cluster_offset, offset_in_cluster,
|
||||
&local_qiov, n_bytes);
|
||||
if (ret) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
bytes -= n_bytes;
|
||||
offset += n_bytes;
|
||||
bytes_done += n_bytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = vmdk_read(bs, sector_num, buf, nb_sectors);
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
|
||||
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.
|
||||
*/
|
||||
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors,
|
||||
bool zeroed, bool zero_dry_run)
|
||||
static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov,
|
||||
bool zeroed, bool zero_dry_run)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
VmdkExtent *extent = NULL;
|
||||
int ret;
|
||||
int64_t index_in_cluster, n;
|
||||
int64_t offset_in_cluster, n_bytes;
|
||||
uint64_t cluster_offset;
|
||||
uint64_t bytes_done = 0;
|
||||
VmdkMetaData m_data;
|
||||
|
||||
if (sector_num > bs->total_sectors) {
|
||||
error_report("Wrong offset: sector_num=0x%" PRIx64
|
||||
if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) {
|
||||
error_report("Wrong offset: offset=0x%" PRIx64
|
||||
" total_sectors=0x%" PRIx64,
|
||||
sector_num, bs->total_sectors);
|
||||
offset, bs->total_sectors);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
extent = find_extent(s, sector_num, extent);
|
||||
while (bytes > 0) {
|
||||
extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent);
|
||||
if (!extent) {
|
||||
return -EIO;
|
||||
}
|
||||
index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num);
|
||||
n = extent->cluster_sectors - index_in_cluster;
|
||||
if (n > nb_sectors) {
|
||||
n = nb_sectors;
|
||||
}
|
||||
ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9,
|
||||
offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset);
|
||||
n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE
|
||||
- offset_in_cluster);
|
||||
|
||||
ret = get_cluster_offset(bs, extent, &m_data, offset,
|
||||
!(extent->compressed || zeroed),
|
||||
&cluster_offset,
|
||||
index_in_cluster, index_in_cluster + n);
|
||||
&cluster_offset, offset_in_cluster,
|
||||
offset_in_cluster + n_bytes);
|
||||
if (extent->compressed) {
|
||||
if (ret == VMDK_OK) {
|
||||
/* Refuse write to allocated cluster for streamOptimized */
|
||||
@ -1546,7 +1584,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EIO;
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
@ -1556,9 +1594,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
if (zeroed) {
|
||||
/* Do zeroed write, buf is ignored */
|
||||
if (extent->has_zero_grain &&
|
||||
index_in_cluster == 0 &&
|
||||
n >= extent->cluster_sectors) {
|
||||
n = extent->cluster_sectors;
|
||||
offset_in_cluster == 0 &&
|
||||
n_bytes >= extent->cluster_sectors * BDRV_SECTOR_SIZE) {
|
||||
n_bytes = extent->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
if (!zero_dry_run) {
|
||||
/* update L2 tables */
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
ret = vmdk_write_extent(extent,
|
||||
cluster_offset, index_in_cluster * 512,
|
||||
buf, n, sector_num);
|
||||
ret = vmdk_write_extent(extent, cluster_offset, offset_in_cluster,
|
||||
qiov, bytes_done, n_bytes, offset);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -1585,9 +1622,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
bytes -= n_bytes;
|
||||
offset += n_bytes;
|
||||
bytes_done += n_bytes;
|
||||
|
||||
/* update CID on the first write every time the virtual disk is
|
||||
* opened */
|
||||
@ -1602,25 +1639,65 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
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);
|
||||
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,
|
||||
int64_t sector_num,
|
||||
const uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
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 {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@ -1633,12 +1710,15 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
/* write zeroes could fail if sectors not aligned to cluster, test it with
|
||||
* 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) {
|
||||
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);
|
||||
return ret;
|
||||
@ -1728,12 +1808,12 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
header.check_bytes[3] = 0xa;
|
||||
|
||||
/* write all the data */
|
||||
ret = blk_pwrite(blk, 0, &magic, sizeof(magic));
|
||||
ret = blk_pwrite(blk, 0, &magic, sizeof(magic), 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, QERR_IO_ERROR);
|
||||
goto exit;
|
||||
}
|
||||
ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header));
|
||||
ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header), 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, QERR_IO_ERROR);
|
||||
goto exit;
|
||||
@ -1753,7 +1833,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
gd_buf[i] = cpu_to_le32(tmp);
|
||||
}
|
||||
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) {
|
||||
error_setg(errp, QERR_IO_ERROR);
|
||||
goto exit;
|
||||
@ -1765,7 +1845,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
gd_buf[i] = cpu_to_le32(tmp);
|
||||
}
|
||||
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) {
|
||||
error_setg(errp, QERR_IO_ERROR);
|
||||
goto exit;
|
||||
@ -1829,8 +1909,8 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
int64_t total_size = 0, filesize;
|
||||
char *adapter_type = NULL;
|
||||
char *backing_file = NULL;
|
||||
char *hw_version = NULL;
|
||||
char *fmt = NULL;
|
||||
int flags = 0;
|
||||
int ret = 0;
|
||||
bool flat, split, compress;
|
||||
GString *ext_desc_lines;
|
||||
@ -1861,7 +1941,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
"# The Disk Data Base\n"
|
||||
"#DDB\n"
|
||||
"\n"
|
||||
"ddb.virtualHWVersion = \"%d\"\n"
|
||||
"ddb.virtualHWVersion = \"%s\"\n"
|
||||
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
|
||||
"ddb.geometry.heads = \"%" PRIu32 "\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
@ -1878,8 +1958,20 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
BDRV_SECTOR_SIZE);
|
||||
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
|
||||
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)) {
|
||||
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);
|
||||
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,
|
||||
parent_desc_line,
|
||||
ext_desc_lines->str,
|
||||
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
||||
hw_version,
|
||||
total_size /
|
||||
(int64_t)(63 * number_heads * BDRV_SECTOR_SIZE),
|
||||
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);
|
||||
|
||||
ret = blk_pwrite(new_blk, desc_offset, desc, desc_len);
|
||||
ret = blk_pwrite(new_blk, desc_offset, desc, desc_len, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not write description");
|
||||
goto exit;
|
||||
@ -2047,6 +2139,7 @@ exit:
|
||||
}
|
||||
g_free(adapter_type);
|
||||
g_free(backing_file);
|
||||
g_free(hw_version);
|
||||
g_free(fmt);
|
||||
g_free(desc);
|
||||
g_free(path);
|
||||
@ -2297,6 +2390,12 @@ static QemuOptsList vmdk_create_opts = {
|
||||
.help = "VMDK version 6 image",
|
||||
.def_value_str = "off"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_HWVERSION,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "VMDK hardware version",
|
||||
.def_value_str = "undefined"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_SUBFMT,
|
||||
.type = QEMU_OPT_STRING,
|
||||
@ -2321,8 +2420,8 @@ static BlockDriver bdrv_vmdk = {
|
||||
.bdrv_open = vmdk_open,
|
||||
.bdrv_check = vmdk_check,
|
||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||
.bdrv_read = vmdk_co_read,
|
||||
.bdrv_write = vmdk_co_write,
|
||||
.bdrv_co_preadv = vmdk_co_preadv,
|
||||
.bdrv_co_pwritev = vmdk_co_pwritev,
|
||||
.bdrv_write_compressed = vmdk_write_compressed,
|
||||
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
||||
.bdrv_close = vmdk_close,
|
||||
|
187
block/vpc.c
187
block/vpc.c
@ -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
|
||||
* operation (the block bitmaps is updated then), 0 otherwise.
|
||||
*/
|
||||
static inline int64_t get_sector_offset(BlockDriverState *bs,
|
||||
int64_t sector_num, int write)
|
||||
static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
|
||||
bool write)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
uint64_t offset = sector_num * 512;
|
||||
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;
|
||||
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)
|
||||
return -1; /* not allocated */
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
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];
|
||||
|
||||
/* Check if sector_num is valid */
|
||||
if ((sector_num < 0) || (sector_num > bs->total_sectors))
|
||||
return -1;
|
||||
if ((offset < 0) || (offset > bs->total_sectors * BDRV_SECTOR_SIZE)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write entry into in-memory BAT */
|
||||
index = (sector_num * 512) / s->block_size;
|
||||
if (s->pagetable[index] != 0xFFFFFFFF)
|
||||
return -1;
|
||||
|
||||
index = offset / s->block_size;
|
||||
assert(s->pagetable[index] == 0xFFFFFFFF);
|
||||
s->pagetable[index] = s->free_data_block_offset / 512;
|
||||
|
||||
/* Initialize the block's bitmap */
|
||||
@ -553,11 +557,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return get_sector_offset(bs, sector_num, 0);
|
||||
return get_image_offset(bs, offset, false);
|
||||
|
||||
fail:
|
||||
s->free_data_block_offset -= (s->block_size + s->bitmap_size);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
@ -573,104 +577,105 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int ret;
|
||||
int64_t offset;
|
||||
int64_t sectors, sectors_per_block;
|
||||
int64_t image_offset;
|
||||
int64_t n_bytes;
|
||||
int64_t bytes_done = 0;
|
||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||
QEMUIOVector local_qiov;
|
||||
|
||||
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;
|
||||
sectors = sectors_per_block - (sector_num % sectors_per_block);
|
||||
if (sectors > nb_sectors) {
|
||||
sectors = nb_sectors;
|
||||
}
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
|
||||
if (offset == -1) {
|
||||
memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
|
||||
while (bytes > 0) {
|
||||
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 {
|
||||
ret = bdrv_pread(bs->file->bs, offset, buf,
|
||||
sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret != sectors * BDRV_SECTOR_SIZE) {
|
||||
return -1;
|
||||
qemu_iovec_reset(&local_qiov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
|
||||
|
||||
ret = bdrv_co_preadv(bs->file->bs, image_offset, n_bytes,
|
||||
&local_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
nb_sectors -= sectors;
|
||||
sector_num += sectors;
|
||||
buf += sectors * BDRV_SECTOR_SIZE;
|
||||
bytes -= n_bytes;
|
||||
offset += n_bytes;
|
||||
bytes_done += n_bytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret;
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = vpc_read(bs, sector_num, buf, nb_sectors);
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vpc_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int64_t offset;
|
||||
int64_t sectors, sectors_per_block;
|
||||
int64_t image_offset;
|
||||
int64_t n_bytes;
|
||||
int64_t bytes_done = 0;
|
||||
int ret;
|
||||
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||
QEMUIOVector local_qiov;
|
||||
|
||||
if (be32_to_cpu(footer->type) == VHD_FIXED) {
|
||||
return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
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 bdrv_co_pwritev(bs->file->bs, offset, bytes, qiov, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -783,13 +788,13 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
|
||||
block_size = 0x200000;
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
@ -799,7 +804,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
|
||||
|
||||
memset(buf, 0xFF, 512);
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
@ -826,7 +831,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
|
||||
/* Write the header */
|
||||
offset = 512;
|
||||
|
||||
ret = blk_pwrite(blk, offset, buf, 1024);
|
||||
ret = blk_pwrite(blk, offset, buf, 1024, 0);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -848,7 +853,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -1056,8 +1061,8 @@ static BlockDriver bdrv_vpc = {
|
||||
.bdrv_reopen_prepare = vpc_reopen_prepare,
|
||||
.bdrv_create = vpc_create,
|
||||
|
||||
.bdrv_read = vpc_co_read,
|
||||
.bdrv_write = vpc_co_write,
|
||||
.bdrv_co_preadv = vpc_co_preadv,
|
||||
.bdrv_co_pwritev = vpc_co_pwritev,
|
||||
.bdrv_co_get_block_status = vpc_co_get_block_status,
|
||||
|
||||
.bdrv_get_info = vpc_get_info,
|
||||
|
@ -1179,6 +1179,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->read_only = 0;
|
||||
}
|
||||
|
||||
bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static coroutine_fn int vvfat_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vvfat_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
ret = vvfat_read(bs, sector_num, buf, nb_sectors);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
qemu_iovec_from_buf(qiov, 0, buf, bytes);
|
||||
g_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2880,14 +2898,31 @@ DLOG(checkpoint());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
static int coroutine_fn
|
||||
vvfat_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret;
|
||||
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);
|
||||
ret = vvfat_write(bs, sector_num, buf, nb_sectors);
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
|
||||
g_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2904,8 +2939,10 @@ static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
|
||||
return BDRV_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t* buffer, int nb_sectors) {
|
||||
static int coroutine_fn
|
||||
write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
|
||||
return try_commit(s);
|
||||
}
|
||||
@ -2918,7 +2955,7 @@ static void write_target_close(BlockDriverState *bs) {
|
||||
|
||||
static BlockDriver vvfat_write_target = {
|
||||
.format_name = "vvfat_write_target",
|
||||
.bdrv_write = write_target_commit,
|
||||
.bdrv_co_pwritev = write_target_commit,
|
||||
.bdrv_close = write_target_close,
|
||||
};
|
||||
|
||||
@ -3014,8 +3051,8 @@ static BlockDriver bdrv_vvfat = {
|
||||
.bdrv_file_open = vvfat_open,
|
||||
.bdrv_close = vvfat_close,
|
||||
|
||||
.bdrv_read = vvfat_co_read,
|
||||
.bdrv_write = vvfat_co_write,
|
||||
.bdrv_co_preadv = vvfat_co_preadv,
|
||||
.bdrv_co_pwritev = vvfat_co_pwritev,
|
||||
.bdrv_co_get_block_status = vvfat_co_get_block_status,
|
||||
};
|
||||
|
||||
|
57
blockdev.c
57
blockdev.c
@ -73,7 +73,7 @@ static int if_max_devs[IF_COUNT] = {
|
||||
* Do not change these numbers! They govern how drive option
|
||||
* 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.
|
||||
* Otherwise, some index values map to "impossible" bus, unit
|
||||
* values.
|
||||
@ -4092,6 +4092,61 @@ out:
|
||||
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 *head = NULL, **p_next = &head;
|
||||
|
@ -73,7 +73,7 @@ typedef struct {
|
||||
BlockBackend *blk;
|
||||
BlockAIOCB *acb;
|
||||
QEMUSGList *sg;
|
||||
uint64_t sector_num;
|
||||
uint64_t offset;
|
||||
DMADirection dir;
|
||||
int sg_cur_index;
|
||||
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);
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
dbs->acb = dbs->io_func(dbs->blk, dbs->sector_num, &dbs->iov,
|
||||
dbs->iov.size / 512, dma_blk_cb, dbs);
|
||||
dbs->acb = dbs->io_func(dbs->blk, dbs->offset, &dbs->iov, 0,
|
||||
dma_blk_cb, dbs);
|
||||
assert(dbs->acb);
|
||||
}
|
||||
|
||||
@ -203,7 +203,7 @@ BlockAIOCB *dma_blk_io(
|
||||
dbs->acb = NULL;
|
||||
dbs->blk = blk;
|
||||
dbs->sg = sg;
|
||||
dbs->sector_num = sector_num;
|
||||
dbs->offset = sector_num << BDRV_SECTOR_BITS;
|
||||
dbs->sg_cur_index = 0;
|
||||
dbs->sg_cur_byte = 0;
|
||||
dbs->dir = dir;
|
||||
@ -219,7 +219,7 @@ BlockAIOCB *dma_blk_read(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,13 @@ static int fd_sector(FDrive *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:
|
||||
* returns 0 if already on right track
|
||||
* 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 ||
|
||||
len < FD_SECTOR_LEN || rel_pos != 0) {
|
||||
/* READ & SCAN commands and realign to a sector for WRITE */
|
||||
if (blk_read(cur_drv->blk, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
if (blk_pread(cur_drv->blk, fd_offset(cur_drv),
|
||||
fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) {
|
||||
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
/* 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,
|
||||
fdctrl->data_pos, len);
|
||||
if (blk_write(cur_drv->blk, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv),
|
||||
fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) {
|
||||
FLOPPY_DPRINTF("error writing sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
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));
|
||||
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) {
|
||||
FLOPPY_DPRINTF("error getting sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
@ -1820,7 +1828,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
|
||||
}
|
||||
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
|
||||
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));
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
|
||||
} else {
|
||||
@ -2243,8 +2252,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
||||
if (pos == FD_SECTOR_LEN - 1 ||
|
||||
fdctrl->data_pos == fdctrl->data_len) {
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
|
||||
< 0) {
|
||||
if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
|
||||
BDRV_SECTOR_SIZE, 0) < 0) {
|
||||
FLOPPY_DPRINTF("error writing sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
break;
|
||||
|
@ -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
|
||||
* 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;
|
||||
}
|
||||
/* test msdos magic */
|
||||
|
@ -358,25 +358,21 @@ static void blk_sync_complete(void *opaque, int ret)
|
||||
|
||||
static void flash_sync_page(Flash *s, int page)
|
||||
{
|
||||
int blk_sector, nb_sectors;
|
||||
QEMUIOVector iov;
|
||||
|
||||
if (!s->blk || blk_is_read_only(s->blk)) {
|
||||
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_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete,
|
||||
NULL);
|
||||
qemu_iovec_add(&iov, s->storage + page * s->pi->page_size,
|
||||
s->pi->page_size);
|
||||
blk_aio_pwritev(s->blk, page * s->pi->page_size, &iov, 0,
|
||||
blk_sync_complete, NULL);
|
||||
}
|
||||
|
||||
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
||||
{
|
||||
int64_t start, end, nb_sectors;
|
||||
QEMUIOVector iov;
|
||||
|
||||
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));
|
||||
start = off / BDRV_SECTOR_SIZE;
|
||||
end = (off + len) / BDRV_SECTOR_SIZE;
|
||||
nb_sectors = end - start;
|
||||
qemu_iovec_init(&iov, 1);
|
||||
qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL);
|
||||
qemu_iovec_add(&iov, s->storage + off, len);
|
||||
blk_aio_pwritev(s->blk, off, &iov, 0, blk_sync_complete, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* FIXME: Move to late init */
|
||||
if (blk_read(s->blk, 0, s->storage,
|
||||
DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) {
|
||||
if (blk_pread(s->blk, 0, s->storage, s->size)) {
|
||||
fprintf(stderr, "Failed to initialize SPI flash!\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -663,7 +663,8 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
||||
sector = SECTOR(s->addr);
|
||||
off = (s->addr & PAGE_MASK) + s->offset;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -675,21 +676,24 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
|
||||
sector = off >> 9;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -716,17 +720,20 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
||||
i = SECTOR(addr);
|
||||
page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
addr = PAGE_START(addr);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@ -734,18 +741,20 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
||||
i = (addr & ~0x1ff) + 0x200;
|
||||
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 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",
|
||||
__func__, 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -760,7 +769,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
|
||||
|
||||
if (s->blk) {
|
||||
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",
|
||||
__func__, SECTOR(addr));
|
||||
}
|
||||
@ -769,8 +779,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
|
||||
OOB_SIZE);
|
||||
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
|
||||
} else {
|
||||
if (blk_read(s->blk, PAGE_START(addr) >> 9,
|
||||
s->io, (PAGE_SECTORS + 2)) < 0) {
|
||||
if (blk_pread(s->blk, PAGE_START(addr), s->io,
|
||||
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n",
|
||||
__func__, PAGE_START(addr) >> 9);
|
||||
}
|
||||
|
@ -224,7 +224,8 @@ static void onenand_reset(OneNANDState *s, int cold)
|
||||
/* Lock the whole flash */
|
||||
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__);
|
||||
}
|
||||
}
|
||||
@ -240,8 +241,11 @@ static void onenand_system_reset(DeviceState *dev)
|
||||
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
|
||||
void *dest)
|
||||
{
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
|
||||
assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
@ -257,19 +261,22 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
|
||||
int result = 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;
|
||||
uint8_t *dp = 0;
|
||||
if (s->blk_cur) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (sec + secn > s->secs_cur) {
|
||||
result = 1;
|
||||
} else {
|
||||
dp = (uint8_t *)s->current + (sec << 9);
|
||||
dp = (uint8_t *)s->current + offset;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
@ -278,7 +285,7 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
|
||||
dp[i] &= sp[i];
|
||||
}
|
||||
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) {
|
||||
@ -295,7 +302,8 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
|
||||
uint8_t buf[512];
|
||||
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -315,10 +323,12 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
|
||||
if (secn > 0) {
|
||||
const uint8_t *sp = (const uint8_t *)src;
|
||||
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) {
|
||||
dp = g_malloc(512);
|
||||
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;
|
||||
} else {
|
||||
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];
|
||||
}
|
||||
if (s->blk_cur) {
|
||||
result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5),
|
||||
dp, 1) < 0;
|
||||
result = blk_pwrite(s->blk_cur, offset, dp,
|
||||
BDRV_SECTOR_SIZE, 0) < 0;
|
||||
}
|
||||
}
|
||||
g_free(dp);
|
||||
@ -355,14 +365,17 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num)
|
||||
for (; num > 0; num--, sec++) {
|
||||
if (s->blk_cur) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
|
@ -413,11 +413,11 @@ static void pflash_update(pflash_t *pfl, int offset,
|
||||
int offset_end;
|
||||
if (pfl->blk) {
|
||||
offset_end = offset + size;
|
||||
/* round to sectors */
|
||||
offset = offset >> 9;
|
||||
offset_end = (offset_end + 511) >> 9;
|
||||
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
/* widen to sector boundaries */
|
||||
offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
|
||||
offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
|
||||
blk_pwrite(pfl->blk, offset, pfl->storage + offset,
|
||||
offset_end - offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -739,7 +739,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
if (pfl->blk) {
|
||||
/* 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) {
|
||||
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
|
||||
|
@ -253,11 +253,11 @@ static void pflash_update(pflash_t *pfl, int offset,
|
||||
int offset_end;
|
||||
if (pfl->blk) {
|
||||
offset_end = offset + size;
|
||||
/* round to sectors */
|
||||
offset = offset >> 9;
|
||||
offset_end = (offset_end + 511) >> 9;
|
||||
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
/* widen to sector boundaries */
|
||||
offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
|
||||
offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
|
||||
blk_pwrite(pfl->blk, offset, pfl->storage + offset,
|
||||
offset_end - offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,7 +622,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
pfl->chip_len = chip_len;
|
||||
if (pfl->blk) {
|
||||
/* 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) {
|
||||
vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||
error_setg(errp, "failed to read the initial flash content");
|
||||
|
@ -322,7 +322,6 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
|
||||
{
|
||||
QEMUIOVector *qiov = &mrb->reqs[start]->qiov;
|
||||
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;
|
||||
|
||||
if (num_reqs > 1) {
|
||||
@ -331,7 +330,7 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
|
||||
int tmp_niov = qiov->niov;
|
||||
|
||||
/* 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. */
|
||||
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,
|
||||
mrb->reqs[i]->qiov.size);
|
||||
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,
|
||||
nb_sectors, is_write);
|
||||
trace_virtio_blk_submit_multireq(mrb, start, num_reqs,
|
||||
sector_num << BDRV_SECTOR_BITS,
|
||||
qiov->size, is_write);
|
||||
block_acct_merge_done(blk_get_stats(blk),
|
||||
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ,
|
||||
num_reqs - 1);
|
||||
}
|
||||
|
||||
if (is_write) {
|
||||
blk_aio_writev(blk, sector_num, qiov, nb_sectors,
|
||||
virtio_blk_rw_complete, mrb->reqs[start]);
|
||||
blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0,
|
||||
virtio_blk_rw_complete, mrb->reqs[start]);
|
||||
} else {
|
||||
blk_aio_readv(blk, sector_num, qiov, nb_sectors,
|
||||
virtio_blk_rw_complete, mrb->reqs[start]);
|
||||
blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0,
|
||||
virtio_blk_rw_complete, mrb->reqs[start]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,9 +554,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
|
||||
ioreq->v.size, BLOCK_ACCT_READ);
|
||||
ioreq->aio_inflight++;
|
||||
blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0,
|
||||
qemu_aio_complete, ioreq);
|
||||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
@ -569,9 +568,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
ioreq->req.operation == BLKIF_OP_WRITE ?
|
||||
BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
|
||||
ioreq->aio_inflight++;
|
||||
blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0,
|
||||
qemu_aio_complete, ioreq);
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
{
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "hw/scsi/scsi.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 padstr8(uint8_t *buf, int buf_size, const char *src)
|
||||
@ -111,7 +114,7 @@ cd_read_sector_sync(IDEState *s)
|
||||
{
|
||||
int ret;
|
||||
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
|
||||
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) {
|
||||
case 2048:
|
||||
ret = blk_read(s->blk, (int64_t)s->lba << 2,
|
||||
s->io_buffer, 4);
|
||||
ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS,
|
||||
s->io_buffer, ATAPI_SECTOR_SIZE);
|
||||
break;
|
||||
case 2352:
|
||||
ret = blk_read(s->blk, (int64_t)s->lba << 2,
|
||||
s->io_buffer + 16, 4);
|
||||
ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS,
|
||||
s->io_buffer + 16, ATAPI_SECTOR_SIZE);
|
||||
if (ret >= 0) {
|
||||
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->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);
|
||||
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
@ -190,7 +193,7 @@ static int cd_read_sector(IDEState *s)
|
||||
#endif
|
||||
|
||||
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,
|
||||
cd_read_sector_cb, s);
|
||||
@ -435,7 +438,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2,
|
||||
|
@ -442,7 +442,7 @@ static void ide_issue_trim_cb(void *opaque, int ret)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TrimAIOCB *iocb;
|
||||
@ -616,8 +616,8 @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
|
||||
req->iov.iov_len = iov->size;
|
||||
qemu_iovec_init_external(&req->qiov, &req->iov, 1);
|
||||
|
||||
aioreq = blk_aio_readv(s->blk, sector_num, &req->qiov, nb_sectors,
|
||||
ide_buffered_readv_cb, req);
|
||||
aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS,
|
||||
&req->qiov, 0, ide_buffered_readv_cb, req);
|
||||
|
||||
QLIST_INSERT_HEAD(&s->buffered_requests, req, list);
|
||||
return aioreq;
|
||||
@ -1006,8 +1006,8 @@ static void ide_sector_write(IDEState *s)
|
||||
|
||||
block_acct_start(blk_get_stats(s->blk), &s->acct,
|
||||
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
|
||||
s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n,
|
||||
ide_sector_write_cb, s);
|
||||
s->pio_aiocb = blk_aio_pwritev(s->blk, sector_num << BDRV_SECTOR_BITS,
|
||||
&s->qiov, 0, ide_sector_write_cb, s);
|
||||
}
|
||||
|
||||
static void ide_flush_cb(void *opaque, int ret)
|
||||
|
@ -614,7 +614,7 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
|
||||
void ide_transfer_stop(IDEState *s);
|
||||
void ide_set_inactive(IDEState *s, bool more);
|
||||
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);
|
||||
BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
|
@ -55,8 +55,8 @@ static const int debug_macio = 0;
|
||||
/*
|
||||
* Unaligned DMA read/write access functions required for OS X/Darwin which
|
||||
* 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
|
||||
* easy to remove if the unaligned block APIs are ever exposed.
|
||||
* modelled on bdrv_co_preadv()/bdrv_co_pwritev() and so should be easy to
|
||||
* remove if the unaligned block APIs are ever exposed.
|
||||
*/
|
||||
|
||||
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 " "
|
||||
"nsector: %x\n", (offset >> 9), (bytes >> 9));
|
||||
|
||||
s->bus->dma->aiocb = blk_aio_readv(blk, (offset >> 9), &io->iov,
|
||||
(bytes >> 9), cb, io);
|
||||
s->bus->dma->aiocb = blk_aio_preadv(blk, offset, &io->iov, 0, cb, io);
|
||||
}
|
||||
|
||||
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 " "
|
||||
"nsector: %x\n", (offset >> 9), (bytes >> 9));
|
||||
|
||||
s->bus->dma->aiocb = blk_aio_writev(blk, (offset >> 9), &io->iov,
|
||||
(bytes >> 9), cb, io);
|
||||
s->bus->dma->aiocb = blk_aio_pwritev(blk, offset, &io->iov, 0, cb, io);
|
||||
}
|
||||
|
||||
static void pmac_dma_trim(BlockBackend *blk,
|
||||
@ -232,8 +230,7 @@ static void pmac_dma_trim(BlockBackend *blk,
|
||||
s->io_buffer_index += io->len;
|
||||
io->len = 0;
|
||||
|
||||
s->bus->dma->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov,
|
||||
(bytes >> 9), cb, io);
|
||||
s->bus->dma->aiocb = ide_issue_trim(blk, offset, &io->iov, 0, cb, io);
|
||||
}
|
||||
|
||||
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||
|
@ -124,7 +124,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
||||
alen = len;
|
||||
if (nvram->blk) {
|
||||
alen = blk_pwrite(nvram->blk, offset, membuf, len);
|
||||
alen = blk_pwrite(nvram->blk, offset, membuf, len, 0);
|
||||
}
|
||||
|
||||
assert(nvram->buf);
|
||||
@ -190,7 +190,7 @@ static int spapr_nvram_post_load(void *opaque, int version_id)
|
||||
sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
|
||||
|
||||
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) {
|
||||
return alen;
|
||||
|
@ -108,7 +108,7 @@ static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
||||
return r->qiov.size / 512;
|
||||
}
|
||||
|
||||
static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
|
||||
@ -316,7 +315,6 @@ done:
|
||||
static void scsi_do_read(SCSIDiskReq *r, int ret)
|
||||
{
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
uint32_t n;
|
||||
|
||||
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,
|
||||
scsi_dma_complete, r);
|
||||
} 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,
|
||||
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
|
||||
r->req.aiocb = blk_aio_readv(s->qdev.conf.blk, r->sector, &r->qiov, n,
|
||||
scsi_read_complete, r);
|
||||
r->qiov.size, BLOCK_ACCT_READ);
|
||||
r->req.aiocb = blk_aio_preadv(s->qdev.conf.blk,
|
||||
r->sector << BDRV_SECTOR_BITS, &r->qiov,
|
||||
0, scsi_read_complete, r);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -504,7 +503,6 @@ static void scsi_write_data(SCSIRequest *req)
|
||||
{
|
||||
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
uint32_t n;
|
||||
|
||||
/* No data transfer may already be in progress */
|
||||
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,
|
||||
scsi_dma_complete, r);
|
||||
} else {
|
||||
n = r->qiov.size / 512;
|
||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
|
||||
n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
|
||||
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, r->sector, &r->qiov, n,
|
||||
scsi_write_complete, r);
|
||||
r->qiov.size, BLOCK_ACCT_WRITE);
|
||||
r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
|
||||
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) {
|
||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
|
||||
data->iov.iov_len, BLOCK_ACCT_WRITE);
|
||||
/* blk_aio_write doesn't like the qiov size being different from
|
||||
* nb_sectors, make sure they match.
|
||||
*/
|
||||
/* Reinitialize qiov, to handle unaligned WRITE SAME request
|
||||
* where final qiov may need smaller size */
|
||||
qemu_iovec_init_external(&data->qiov, &data->iov, 1);
|
||||
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
|
||||
&data->qiov, data->iov.iov_len / 512,
|
||||
scsi_write_same_complete, data);
|
||||
r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
|
||||
data->sector << BDRV_SECTOR_BITS,
|
||||
&data->qiov, 0,
|
||||
scsi_write_same_complete, data);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1781,8 +1779,8 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
nb_sectors * s->qdev.blocksize,
|
||||
BLOCK_ACCT_WRITE);
|
||||
r->req.aiocb = blk_aio_write_zeroes(s->qdev.conf.blk,
|
||||
r->req.cmd.lba * (s->qdev.blocksize / 512),
|
||||
nb_sectors * (s->qdev.blocksize / 512),
|
||||
r->req.cmd.lba * s->qdev.blocksize,
|
||||
nb_sectors * s->qdev.blocksize,
|
||||
flags, scsi_aio_complete, r);
|
||||
return;
|
||||
}
|
||||
@ -1803,9 +1801,10 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
|
||||
scsi_req_ref(&r->req);
|
||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
|
||||
data->iov.iov_len, BLOCK_ACCT_WRITE);
|
||||
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
|
||||
&data->qiov, data->iov.iov_len / 512,
|
||||
scsi_write_same_complete, data);
|
||||
r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
|
||||
data->sector << BDRV_SECTOR_BITS,
|
||||
&data->qiov, 0,
|
||||
scsi_write_same_complete, data);
|
||||
}
|
||||
|
||||
static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
||||
|
51
hw/sd/sd.c
51
hw/sd/sd.c
@ -123,7 +123,6 @@ struct SDState {
|
||||
qemu_irq readonly_cb;
|
||||
qemu_irq inserted_cb;
|
||||
BlockBackend *blk;
|
||||
uint8_t *buf;
|
||||
|
||||
bool enable;
|
||||
};
|
||||
@ -551,7 +550,7 @@ static const VMStateDescription sd_vmstate = {
|
||||
VMSTATE_UINT64(data_start, SDState),
|
||||
VMSTATE_UINT32(data_offset, SDState),
|
||||
VMSTATE_UINT8_ARRAY(data, SDState, 512),
|
||||
VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
|
||||
VMSTATE_UNUSED_V(1, 512),
|
||||
VMSTATE_BOOL(enable, SDState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
@ -1577,57 +1576,17 @@ send_response:
|
||||
|
||||
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",
|
||||
(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");
|
||||
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)
|
||||
{
|
||||
uint64_t end = addr + len;
|
||||
|
||||
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");
|
||||
}
|
||||
if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 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;
|
||||
}
|
||||
|
||||
sd->buf = blk_blockalign(sd->blk, 512);
|
||||
|
||||
if (sd->blk) {
|
||||
blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
|
||||
}
|
||||
|
@ -476,6 +476,10 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
|
||||
void bdrv_ref(BlockDriverState *bs);
|
||||
void bdrv_unref(BlockDriverState *bs);
|
||||
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);
|
||||
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_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:
|
||||
@ -541,4 +546,8 @@ void bdrv_drained_begin(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
|
||||
|
@ -38,12 +38,12 @@
|
||||
#include "qemu/throttle.h"
|
||||
|
||||
#define BLOCK_FLAG_ENCRYPT 1
|
||||
#define BLOCK_FLAG_COMPAT6 4
|
||||
#define BLOCK_FLAG_LAZY_REFCOUNTS 8
|
||||
|
||||
#define BLOCK_OPT_SIZE "size"
|
||||
#define BLOCK_OPT_ENCRYPT "encryption"
|
||||
#define BLOCK_OPT_COMPAT6 "compat6"
|
||||
#define BLOCK_OPT_HWVERSION "hwversion"
|
||||
#define BLOCK_OPT_BACKING_FILE "backing_file"
|
||||
#define BLOCK_OPT_BACKING_FMT "backing_fmt"
|
||||
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
|
||||
@ -127,10 +127,6 @@ struct BlockDriver {
|
||||
Error **errp);
|
||||
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
|
||||
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);
|
||||
int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp);
|
||||
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
||||
@ -153,18 +149,20 @@ struct BlockDriver {
|
||||
|
||||
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
|
||||
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,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
|
||||
int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
|
||||
|
||||
int supported_write_flags;
|
||||
int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs,
|
||||
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
|
||||
|
||||
/*
|
||||
* Efficiently zero a region of the disk image. Typically an image format
|
||||
* would use a compact metadata representation to implement this. This
|
||||
* function pointer may be NULL and .bdrv_co_writev() will be called
|
||||
* instead.
|
||||
* function pointer may be NULL or return -ENOSUP and .bdrv_co_writev()
|
||||
* will be called instead.
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
|
||||
@ -294,7 +292,6 @@ struct BlockDriver {
|
||||
/* io queue for linux-aio */
|
||||
void (*bdrv_io_plug)(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.
|
||||
@ -317,6 +314,11 @@ struct BlockDriver {
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
@ -424,10 +426,10 @@ struct BlockDriverState {
|
||||
|
||||
/* I/O throttling.
|
||||
* throttle_state tells us if this BDS has I/O limits configured.
|
||||
* io_limits_enabled tells us if they are currently being
|
||||
* enforced, but it can be temporarily set to false */
|
||||
* io_limits_disabled tells us if they are currently being enforced */
|
||||
CoQueue throttled_reqs[2];
|
||||
bool io_limits_enabled;
|
||||
unsigned int io_limits_disabled;
|
||||
|
||||
/* The following fields are protected by the ThrottleGroup lock.
|
||||
* See the ThrottleGroup documentation for details. */
|
||||
ThrottleState *throttle_state;
|
||||
@ -446,6 +448,11 @@ struct BlockDriverState {
|
||||
|
||||
/* Alignment requirement for offset/length of I/O requests */
|
||||
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. */
|
||||
char node_name[32];
|
||||
@ -484,6 +491,10 @@ struct BlockDriverState {
|
||||
uint64_t write_threshold_offset;
|
||||
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;
|
||||
};
|
||||
|
||||
@ -517,10 +528,10 @@ extern BlockDriver bdrv_qcow2;
|
||||
*/
|
||||
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,
|
||||
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,
|
||||
BdrvRequestFlags flags);
|
||||
|
||||
@ -713,6 +724,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
const BdrvChildRole *child_role);
|
||||
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);
|
||||
bool blk_dev_has_removable_media(BlockBackend *blk);
|
||||
bool blk_dev_has_tray(BlockBackend *blk);
|
||||
|
@ -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_unregister_bs(BlockDriverState *bs);
|
||||
void throttle_group_restart_bs(BlockDriverState *bs);
|
||||
|
||||
void coroutine_fn throttle_group_co_io_limits_intercept(BlockDriverState *bs,
|
||||
unsigned int bytes,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QEMU Block backends
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
* Copyright (C) 2014-2016 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* 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_get_attached_dev(BlockBackend *blk);
|
||||
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 nb_sectors);
|
||||
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
|
||||
int nb_sectors);
|
||||
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
|
||||
int nb_sectors);
|
||||
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,
|
||||
int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
int count);
|
||||
int blk_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, BdrvRequestFlags flags);
|
||||
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
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);
|
||||
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr);
|
||||
int64_t blk_nb_sectors(BlockBackend *blk);
|
||||
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags,
|
||||
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,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
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,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags);
|
||||
int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset,
|
||||
int count, BdrvRequestFlags flags);
|
||||
int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int blk_truncate(BlockBackend *blk, int64_t offset);
|
||||
|
@ -197,8 +197,8 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
|
||||
void qemu_sglist_destroy(QEMUSGList *qsg);
|
||||
#endif
|
||||
|
||||
typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
typedef BlockAIOCB *DMAIOFunc(BlockBackend *blk, int64_t offset,
|
||||
QEMUIOVector *iov, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
|
||||
BlockAIOCB *dma_blk_io(BlockBackend *blk,
|
||||
|
@ -1115,7 +1115,7 @@ static void nbd_trip(void *opaque)
|
||||
TRACE("Writing to device");
|
||||
|
||||
ret = blk_pwrite(exp->blk, request.from + exp->dev_offset,
|
||||
req->data, request.len);
|
||||
req->data, request.len, 0);
|
||||
if (ret < 0) {
|
||||
LOG("writing to file failed");
|
||||
reply.error = -ret;
|
||||
|
@ -2556,3 +2556,35 @@
|
||||
##
|
||||
{ 'command': 'block-set-write-threshold',
|
||||
'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' } }
|
||||
|
@ -693,6 +693,9 @@ Supported options:
|
||||
File name of a base image (see @option{create} subcommand).
|
||||
@item compat6
|
||||
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
|
||||
Specifies which VMDK subformat to use. Valid options are
|
||||
@code{monolithicSparse} (default),
|
||||
|
46
qemu-img.c
46
qemu-img.c
@ -1088,7 +1088,8 @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num,
|
||||
uint8_t *buffer, bool quiet)
|
||||
{
|
||||
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) {
|
||||
error_report("Error while reading offset %" PRId64 " of %s: %s",
|
||||
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);
|
||||
} else if (allocated1 == allocated2) {
|
||||
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) {
|
||||
error_report("Error while reading offset %" PRId64 " of %s:"
|
||||
" %s", sectors_to_bytes(sector_num), filename1,
|
||||
@ -1309,7 +1311,8 @@ static int img_compare(int argc, char **argv)
|
||||
ret = 4;
|
||||
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) {
|
||||
error_report("Error while reading offset %" PRId64
|
||||
" 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) {
|
||||
/* Without a target backing file we must copy over the contents of
|
||||
* 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
|
||||
* 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 {
|
||||
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];
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -1577,7 +1593,8 @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
|
||||
if (!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) {
|
||||
return ret;
|
||||
}
|
||||
@ -1589,7 +1606,8 @@ static int convert_write(ImgConvertState *s, int64_t sector_num, int nb_sectors,
|
||||
if (s->has_zero_init) {
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -3023,7 +3041,8 @@ static int img_rebase(int argc, char **argv)
|
||||
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) {
|
||||
error_report("error while reading from old backing file");
|
||||
goto out;
|
||||
@ -3037,7 +3056,8 @@ static int img_rebase(int argc, char **argv)
|
||||
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) {
|
||||
error_report("error while reading from new backing file");
|
||||
goto out;
|
||||
@ -3053,8 +3073,10 @@ static int img_rebase(int argc, char **argv)
|
||||
if (compare_sectors(buf_old + written * 512,
|
||||
buf_new + written * 512, n - written, &pnum))
|
||||
{
|
||||
ret = blk_write(blk, sector + written,
|
||||
buf_old + written * 512, pnum);
|
||||
ret = blk_pwrite(blk,
|
||||
(sector + written) << BDRV_SECTOR_BITS,
|
||||
buf_old + written * 512,
|
||||
pnum << BDRV_SECTOR_BITS, 0);
|
||||
if (ret < 0) {
|
||||
error_report("Error while writing to COW image: %s",
|
||||
strerror(-ret));
|
||||
|
283
qemu-io-cmds.c
283
qemu-io-cmds.c
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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,
|
||||
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];
|
||||
|
||||
@ -395,12 +395,6 @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (len & 0x1ff) {
|
||||
printf("length argument %" PRId64
|
||||
" is not sector aligned\n", len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sizes[i] = len;
|
||||
count += len;
|
||||
}
|
||||
@ -419,40 +413,6 @@ fail:
|
||||
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,
|
||||
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,
|
||||
int64_t count, int64_t *total)
|
||||
int64_t count, int flags, int64_t *total)
|
||||
{
|
||||
if (count > INT_MAX) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
*total = blk_pwrite(blk, offset, (uint8_t *)buf, count);
|
||||
*total = blk_pwrite(blk, offset, (uint8_t *)buf, count, flags);
|
||||
if (*total < 0) {
|
||||
return *total;
|
||||
}
|
||||
@ -486,6 +446,7 @@ typedef struct {
|
||||
int64_t offset;
|
||||
int64_t count;
|
||||
int64_t *total;
|
||||
int flags;
|
||||
int ret;
|
||||
bool done;
|
||||
} CoWriteZeroes;
|
||||
@ -494,8 +455,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
|
||||
{
|
||||
CoWriteZeroes *data = opaque;
|
||||
|
||||
data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE,
|
||||
data->count / BDRV_SECTOR_SIZE, 0);
|
||||
data->ret = blk_co_write_zeroes(data->blk, data->offset, data->count,
|
||||
data->flags);
|
||||
data->done = true;
|
||||
if (data->ret < 0) {
|
||||
*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,
|
||||
int64_t *total)
|
||||
int flags, int64_t *total)
|
||||
{
|
||||
Coroutine *co;
|
||||
CoWriteZeroes data = {
|
||||
@ -514,6 +475,7 @@ static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
|
||||
.offset = offset,
|
||||
.count = count,
|
||||
.total = total,
|
||||
.flags = flags,
|
||||
.done = false,
|
||||
};
|
||||
|
||||
@ -589,8 +551,7 @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
|
||||
{
|
||||
int async_ret = NOT_DONE;
|
||||
|
||||
blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9,
|
||||
aio_rw_done, &async_ret);
|
||||
blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret);
|
||||
while (async_ret == NOT_DONE) {
|
||||
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,
|
||||
int64_t offset, int *total)
|
||||
int64_t offset, int flags, int *total)
|
||||
{
|
||||
int async_ret = NOT_DONE;
|
||||
|
||||
blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9,
|
||||
aio_rw_done, &async_ret);
|
||||
blk_aio_pwritev(blk, offset, qiov, flags, aio_rw_done, &async_ret);
|
||||
while (async_ret == NOT_DONE) {
|
||||
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"
|
||||
" -C, -- report statistics in a machine parsable format\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"
|
||||
" -q, -- quiet mode, do not show I/O statistics\n"
|
||||
" -s, -- start offset for pattern verification (only with -P)\n"
|
||||
@ -687,7 +647,7 @@ static const cmdinfo_t read_cmd = {
|
||||
.cfunc = read_f,
|
||||
.argmin = 2,
|
||||
.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",
|
||||
.help = read_help,
|
||||
};
|
||||
@ -695,8 +655,8 @@ static const cmdinfo_t read_cmd = {
|
||||
static int read_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
|
||||
int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
|
||||
bool Cflag = false, qflag = false, vflag = false;
|
||||
bool Pflag = false, sflag = false, lflag = false, bflag = false;
|
||||
int c, cnt;
|
||||
char *buf;
|
||||
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) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
bflag = 1;
|
||||
bflag = true;
|
||||
break;
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'l':
|
||||
lflag = 1;
|
||||
lflag = true;
|
||||
pattern_count = cvtnum(optarg);
|
||||
if (pattern_count < 0) {
|
||||
print_cvtnum_err(pattern_count, optarg);
|
||||
@ -723,20 +683,20 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
/* Ignored for backwards compatibility */
|
||||
break;
|
||||
case 'P':
|
||||
Pflag = 1;
|
||||
Pflag = true;
|
||||
pattern = parse_pattern(optarg);
|
||||
if (pattern < 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
sflag = true;
|
||||
pattern_offset = cvtnum(optarg);
|
||||
if (pattern_offset < 0) {
|
||||
print_cvtnum_err(pattern_offset, optarg);
|
||||
@ -744,7 +704,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
vflag = true;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
}
|
||||
|
||||
if (bflag && pflag) {
|
||||
printf("-b and -p cannot be specified at the same time\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = cvtnum(argv[optind]);
|
||||
if (offset < 0) {
|
||||
print_cvtnum_err(offset, argv[optind]);
|
||||
@ -790,7 +745,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pflag) {
|
||||
if (bflag) {
|
||||
if (offset & 0x1ff) {
|
||||
printf("offset %" PRId64 " is not sector aligned\n",
|
||||
offset);
|
||||
@ -806,12 +761,10 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
|
||||
buf = qemu_io_alloc(blk, count, 0xab);
|
||||
|
||||
gettimeofday(&t1, NULL);
|
||||
if (pflag) {
|
||||
cnt = do_pread(blk, buf, offset, count, &total);
|
||||
} else if (bflag) {
|
||||
if (bflag) {
|
||||
cnt = do_load_vmstate(blk, buf, offset, count, &total);
|
||||
} else {
|
||||
cnt = do_read(blk, buf, offset, count, &total);
|
||||
cnt = do_pread(blk, buf, offset, count, &total);
|
||||
}
|
||||
gettimeofday(&t2, NULL);
|
||||
|
||||
@ -875,7 +828,7 @@ static const cmdinfo_t readv_cmd = {
|
||||
.cfunc = readv_f,
|
||||
.argmin = 2,
|
||||
.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",
|
||||
.help = readv_help,
|
||||
};
|
||||
@ -883,7 +836,7 @@ static const cmdinfo_t readv_cmd = {
|
||||
static int readv_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, qflag = 0, vflag = 0;
|
||||
bool Cflag = false, qflag = false, vflag = false;
|
||||
int c, cnt;
|
||||
char *buf;
|
||||
int64_t offset;
|
||||
@ -892,25 +845,25 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
|
||||
int nr_iov;
|
||||
QEMUIOVector qiov;
|
||||
int pattern = 0;
|
||||
int Pflag = 0;
|
||||
bool Pflag = false;
|
||||
|
||||
while ((c = getopt(argc, argv, "CP:qv")) != -1) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'P':
|
||||
Pflag = 1;
|
||||
Pflag = true;
|
||||
pattern = parse_pattern(optarg);
|
||||
if (pattern < 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
vflag = true;
|
||||
break;
|
||||
default:
|
||||
return qemuio_command_usage(&readv_cmd);
|
||||
@ -929,12 +882,6 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
optind++;
|
||||
|
||||
if (offset & 0x1ff) {
|
||||
printf("offset %" PRId64 " is not sector aligned\n",
|
||||
offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nr_iov = argc - optind;
|
||||
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
|
||||
if (buf == NULL) {
|
||||
@ -991,10 +938,12 @@ static void write_help(void)
|
||||
" filled with a set pattern (0xcdcdcdcd).\n"
|
||||
" -b, -- write to the VM state rather than the virtual disk\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"
|
||||
" -C, -- report statistics in a machine parsable format\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"
|
||||
"\n");
|
||||
}
|
||||
@ -1007,7 +956,7 @@ static const cmdinfo_t write_cmd = {
|
||||
.cfunc = write_f,
|
||||
.argmin = 2,
|
||||
.argmax = -1,
|
||||
.args = "[-bcCpqz] [-P pattern ] off len",
|
||||
.args = "[-bcCfquz] [-P pattern] off len",
|
||||
.oneline = "writes a number of bytes at a specified offset",
|
||||
.help = write_help,
|
||||
};
|
||||
@ -1015,8 +964,9 @@ static const cmdinfo_t write_cmd = {
|
||||
static int write_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
|
||||
int cflag = 0;
|
||||
bool Cflag = false, qflag = false, bflag = false;
|
||||
bool Pflag = false, zflag = false, cflag = false;
|
||||
int flags = 0;
|
||||
int c, cnt;
|
||||
char *buf = NULL;
|
||||
int64_t offset;
|
||||
@ -1025,32 +975,38 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
|
||||
int64_t total = 0;
|
||||
int pattern = 0xcd;
|
||||
|
||||
while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) {
|
||||
while ((c = getopt(argc, argv, "bcCfpP:quz")) != -1) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
bflag = 1;
|
||||
bflag = true;
|
||||
break;
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
cflag = true;
|
||||
break;
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= BDRV_REQ_FUA;
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
/* Ignored for backwards compatibility */
|
||||
break;
|
||||
case 'P':
|
||||
Pflag = 1;
|
||||
Pflag = true;
|
||||
pattern = parse_pattern(optarg);
|
||||
if (pattern < 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
break;
|
||||
case 'z':
|
||||
zflag = 1;
|
||||
zflag = true;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
}
|
||||
|
||||
if (bflag + pflag + zflag > 1) {
|
||||
printf("-b, -p, or -z cannot be specified at the same time\n");
|
||||
if (bflag && zflag) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1088,7 +1054,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pflag) {
|
||||
if (bflag || cflag) {
|
||||
if (offset & 0x1ff) {
|
||||
printf("offset %" PRId64 " is not sector aligned\n",
|
||||
offset);
|
||||
@ -1107,16 +1073,14 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
|
||||
gettimeofday(&t1, NULL);
|
||||
if (pflag) {
|
||||
cnt = do_pwrite(blk, buf, offset, count, &total);
|
||||
} else if (bflag) {
|
||||
if (bflag) {
|
||||
cnt = do_save_vmstate(blk, buf, offset, count, &total);
|
||||
} 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) {
|
||||
cnt = do_write_compressed(blk, buf, offset, count, &total);
|
||||
} else {
|
||||
cnt = do_write(blk, buf, offset, count, &total);
|
||||
cnt = do_pwrite(blk, buf, offset, count, flags, &total);
|
||||
}
|
||||
gettimeofday(&t2, NULL);
|
||||
|
||||
@ -1155,6 +1119,7 @@ writev_help(void)
|
||||
" filled with a set pattern (0xcdcdcdcd).\n"
|
||||
" -P, -- use different pattern to fill file\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"
|
||||
"\n");
|
||||
}
|
||||
@ -1166,7 +1131,7 @@ static const cmdinfo_t writev_cmd = {
|
||||
.cfunc = writev_f,
|
||||
.argmin = 2,
|
||||
.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",
|
||||
.help = writev_help,
|
||||
};
|
||||
@ -1174,7 +1139,8 @@ static const cmdinfo_t writev_cmd = {
|
||||
static int writev_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, qflag = 0;
|
||||
bool Cflag = false, qflag = false;
|
||||
int flags = 0;
|
||||
int c, cnt;
|
||||
char *buf;
|
||||
int64_t offset;
|
||||
@ -1187,10 +1153,13 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "CqP:")) != -1) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= BDRV_REQ_FUA;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
case 'P':
|
||||
pattern = parse_pattern(optarg);
|
||||
@ -1214,12 +1183,6 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
optind++;
|
||||
|
||||
if (offset & 0x1ff) {
|
||||
printf("offset %" PRId64 " is not sector aligned\n",
|
||||
offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nr_iov = argc - optind;
|
||||
buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
|
||||
if (buf == NULL) {
|
||||
@ -1227,7 +1190,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
|
||||
gettimeofday(&t1, NULL);
|
||||
cnt = do_aio_writev(blk, &qiov, offset, &total);
|
||||
cnt = do_aio_writev(blk, &qiov, offset, flags, &total);
|
||||
gettimeofday(&t2, NULL);
|
||||
|
||||
if (cnt < 0) {
|
||||
@ -1283,7 +1246,7 @@ static const cmdinfo_t multiwrite_cmd = {
|
||||
static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, qflag = 0;
|
||||
bool Cflag = false, qflag = false;
|
||||
int c, cnt;
|
||||
char **buf;
|
||||
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) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
case 'P':
|
||||
pattern = parse_pattern(optarg);
|
||||
@ -1412,11 +1375,11 @@ struct aio_ctx {
|
||||
QEMUIOVector qiov;
|
||||
int64_t offset;
|
||||
char *buf;
|
||||
int qflag;
|
||||
int vflag;
|
||||
int Cflag;
|
||||
int Pflag;
|
||||
int zflag;
|
||||
bool qflag;
|
||||
bool vflag;
|
||||
bool Cflag;
|
||||
bool Pflag;
|
||||
bool zflag;
|
||||
BlockAcctCookie acct;
|
||||
int pattern;
|
||||
struct timeval t1;
|
||||
@ -1525,7 +1488,7 @@ static const cmdinfo_t aio_read_cmd = {
|
||||
.cfunc = aio_read_f,
|
||||
.argmin = 2,
|
||||
.argmax = -1,
|
||||
.args = "[-Cqv] [-P pattern ] off len [len..]",
|
||||
.args = "[-Cqv] [-P pattern] off len [len..]",
|
||||
.oneline = "asynchronously reads a number of bytes",
|
||||
.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) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
ctx->Cflag = 1;
|
||||
ctx->Cflag = true;
|
||||
break;
|
||||
case 'P':
|
||||
ctx->Pflag = 1;
|
||||
ctx->Pflag = true;
|
||||
ctx->pattern = parse_pattern(optarg);
|
||||
if (ctx->pattern < 0) {
|
||||
g_free(ctx);
|
||||
@ -1550,10 +1513,10 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
ctx->qflag = 1;
|
||||
ctx->qflag = true;
|
||||
break;
|
||||
case 'v':
|
||||
ctx->vflag = 1;
|
||||
ctx->vflag = true;
|
||||
break;
|
||||
default:
|
||||
g_free(ctx);
|
||||
@ -1574,14 +1537,6 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
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;
|
||||
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
|
||||
if (ctx->buf == NULL) {
|
||||
@ -1593,8 +1548,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
|
||||
gettimeofday(&ctx->t1, NULL);
|
||||
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
|
||||
BLOCK_ACCT_READ);
|
||||
blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov,
|
||||
ctx->qiov.size >> 9, aio_read_done, ctx);
|
||||
blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1614,7 +1568,9 @@ static void aio_write_help(void)
|
||||
" used to ensure all outstanding aio requests have been completed.\n"
|
||||
" -P, -- use different pattern to fill file\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"
|
||||
" -u, -- with -z, allow unmapping\n"
|
||||
" -z, -- write zeroes using blk_aio_write_zeroes\n"
|
||||
"\n");
|
||||
}
|
||||
@ -1626,7 +1582,7 @@ static const cmdinfo_t aio_write_cmd = {
|
||||
.cfunc = aio_write_f,
|
||||
.argmin = 2,
|
||||
.argmax = -1,
|
||||
.args = "[-Cqz] [-P pattern ] off len [len..]",
|
||||
.args = "[-Cfquz] [-P pattern] off len [len..]",
|
||||
.oneline = "asynchronously writes a number of bytes",
|
||||
.help = aio_write_help,
|
||||
};
|
||||
@ -1636,15 +1592,22 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
|
||||
int nr_iov, c;
|
||||
int pattern = 0xcd;
|
||||
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
|
||||
int flags = 0;
|
||||
|
||||
ctx->blk = blk;
|
||||
while ((c = getopt(argc, argv, "CqP:z")) != -1) {
|
||||
while ((c = getopt(argc, argv, "CfqP:z")) != -1) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
ctx->Cflag = 1;
|
||||
ctx->Cflag = true;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= BDRV_REQ_FUA;
|
||||
break;
|
||||
case 'q':
|
||||
ctx->qflag = 1;
|
||||
ctx->qflag = true;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
break;
|
||||
case 'P':
|
||||
pattern = parse_pattern(optarg);
|
||||
@ -1654,7 +1617,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
ctx->zflag = 1;
|
||||
ctx->zflag = true;
|
||||
break;
|
||||
default:
|
||||
g_free(ctx);
|
||||
@ -1673,6 +1636,11 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
|
||||
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) {
|
||||
printf("-z and -P cannot be specified at the same time\n");
|
||||
g_free(ctx);
|
||||
@ -1687,24 +1655,17 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
|
||||
}
|
||||
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) {
|
||||
int64_t count = cvtnum(argv[optind]);
|
||||
if (count < 0) {
|
||||
print_cvtnum_err(count, argv[optind]);
|
||||
g_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->qiov.size = count;
|
||||
blk_aio_write_zeroes(blk, ctx->offset >> 9, count >> 9, 0,
|
||||
aio_write_done, ctx);
|
||||
blk_aio_write_zeroes(blk, ctx->offset, count, flags, aio_write_done,
|
||||
ctx);
|
||||
} else {
|
||||
nr_iov = argc - optind;
|
||||
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_WRITE);
|
||||
|
||||
blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov,
|
||||
ctx->qiov.size >> 9, aio_write_done, ctx);
|
||||
blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
|
||||
ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1884,17 +1845,17 @@ static const cmdinfo_t discard_cmd = {
|
||||
static int discard_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
struct timeval t1, t2;
|
||||
int Cflag = 0, qflag = 0;
|
||||
bool Cflag = false, qflag = false;
|
||||
int c, ret;
|
||||
int64_t offset, count;
|
||||
|
||||
while ((c = getopt(argc, argv, "Cq")) != -1) {
|
||||
switch (c) {
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
Cflag = true;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
qflag = true;
|
||||
break;
|
||||
default:
|
||||
return qemuio_command_usage(&discard_cmd);
|
||||
|
40
qemu-io.c
40
qemu-io.c
@ -101,12 +101,15 @@ static void open_help(void)
|
||||
" opens a new file in the requested mode\n"
|
||||
"\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"
|
||||
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
|
||||
" -r, -- open file read-only\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"
|
||||
"\n");
|
||||
}
|
||||
@ -120,7 +123,7 @@ static const cmdinfo_t open_cmd = {
|
||||
.argmin = 1,
|
||||
.argmax = -1,
|
||||
.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",
|
||||
.help = open_help,
|
||||
};
|
||||
@ -137,14 +140,14 @@ static QemuOptsList empty_opts = {
|
||||
|
||||
static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
{
|
||||
int flags = 0;
|
||||
int flags = BDRV_O_UNMAP;
|
||||
int readonly = 0;
|
||||
bool writethrough = true;
|
||||
int c;
|
||||
QemuOpts *qopts;
|
||||
QDict *opts;
|
||||
|
||||
while ((c = getopt(argc, argv, "snrgo:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "snro:kt:d:")) != -1) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
flags |= BDRV_O_SNAPSHOT;
|
||||
@ -156,9 +159,27 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
case 'r':
|
||||
readonly = 1;
|
||||
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':
|
||||
if (imageOpts) {
|
||||
printf("--image-opts and 'open -o' are mutually exclusive\n");
|
||||
qemu_opts_reset(&empty_opts);
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n"
|
||||
"Usage: %s [OPTIONS]... [-c STRING]... [file]\n"
|
||||
"QEMU Disk exerciser\n"
|
||||
"\n"
|
||||
" --object OBJECTDEF define an object such as 'secret' for\n"
|
||||
" passwords and/or encryption keys\n"
|
||||
" --image-opts treat file as option string\n"
|
||||
" -c, --cmd STRING execute command with its arguments\n"
|
||||
" from the given string\n"
|
||||
" -f, --format FMT specifies the block driver to use\n"
|
||||
" -r, --read-only export read-only\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"
|
||||
" -k, --native-aio use kernel AIO implementation (on Linux only)\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"
|
||||
" -h, --help display this help 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 readonly = 0;
|
||||
const char *sopt = "hVc:d:f:rsnmgkt:T:";
|
||||
const char *sopt = "hVc:d:f:rsnmkt:T:";
|
||||
const struct option lopt[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "offset", required_argument, NULL, 'o' },
|
||||
{ "cmd", required_argument, NULL, 'c' },
|
||||
{ "format", required_argument, NULL, 'f' },
|
||||
{ "read-only", no_argument, NULL, 'r' },
|
||||
|
13
qemu-nbd.c
13
qemu-nbd.c
@ -46,6 +46,8 @@
|
||||
#define QEMU_NBD_OPT_TLSCREDS 261
|
||||
#define QEMU_NBD_OPT_IMAGE_OPTS 262
|
||||
|
||||
#define MBR_SIZE 512
|
||||
|
||||
static NBDExport *exp;
|
||||
static bool newproto;
|
||||
static int verbose;
|
||||
@ -159,12 +161,13 @@ static int find_partition(BlockBackend *blk, int partition,
|
||||
off_t *offset, off_t *size)
|
||||
{
|
||||
struct partition_record mbr[4];
|
||||
uint8_t data[512];
|
||||
uint8_t data[MBR_SIZE];
|
||||
int i;
|
||||
int ext_partnum = 4;
|
||||
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));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -182,10 +185,12 @@ static int find_partition(BlockBackend *blk, int partition,
|
||||
|
||||
if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
|
||||
struct partition_record ext[4];
|
||||
uint8_t data1[512];
|
||||
uint8_t data1[MBR_SIZE];
|
||||
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));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -4395,6 +4395,59 @@ Example:
|
||||
|
||||
<- { "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
|
||||
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.rc
|
||||
. ./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_os Linux
|
||||
|
||||
|
@ -43,13 +43,16 @@ _supported_fmt generic
|
||||
_supported_proto file
|
||||
_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
|
||||
_make_test_img $size
|
||||
|
||||
echo
|
||||
echo "== mark image read-only"
|
||||
chmod a-w "$TEST_IMG"
|
||||
chmod a-w "$TEST_IMG_FILE"
|
||||
|
||||
echo
|
||||
echo "== read from read-only image"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,9 +12,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
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
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
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
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
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
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
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
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
|
@ -31,13 +31,13 @@ _cleanup()
|
||||
{
|
||||
echo "Cleanup"
|
||||
_cleanup_test_img
|
||||
rm "${TEST_IMG2}"
|
||||
rm "${TEST_IMG_FILE2}"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
_compare()
|
||||
{
|
||||
$QEMU_IMG compare "$@" "$TEST_IMG" "${TEST_IMG2}"
|
||||
$QEMU_IMG compare $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" "${TEST_IMG2}"
|
||||
echo $?
|
||||
}
|
||||
|
||||
@ -46,25 +46,37 @@ _compare()
|
||||
. ./common.filter
|
||||
. ./common.pattern
|
||||
|
||||
_supported_fmt raw qcow qcow2 qed
|
||||
_supported_fmt raw qcow qcow2 qed luks
|
||||
_supported_proto file
|
||||
_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
|
||||
TEST_IMG2=$TEST_IMG.2
|
||||
TEST_IMG_FILE2=$TEST_IMG_FILE.2
|
||||
CLUSTER_SIZE=4096
|
||||
size=1024M
|
||||
size=128M
|
||||
|
||||
_make_test_img $size
|
||||
io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45
|
||||
|
||||
# Compare identical images
|
||||
cp "$TEST_IMG" "${TEST_IMG2}"
|
||||
cp "$TEST_IMG_FILE" "${TEST_IMG_FILE2}"
|
||||
_compare
|
||||
_compare -q
|
||||
|
||||
# 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 -s
|
||||
|
||||
@ -77,7 +89,7 @@ _compare
|
||||
# Test unaligned case of mismatch offsets in allocated clusters
|
||||
_make_test_img $size
|
||||
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
|
||||
_compare
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
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
|
||||
wrote 4096/4096 bytes at offset 524288
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@ -13,6 +13,8 @@ Images are identical.
|
||||
0
|
||||
0
|
||||
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!
|
||||
Images are identical.
|
||||
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)
|
||||
Content mismatch at offset 0!
|
||||
1
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
=== IO: pattern 100
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
@ -47,6 +47,10 @@ _supported_cache_modes "writeback" "writethrough" "unsafe"
|
||||
size=128M
|
||||
_make_test_img $size
|
||||
|
||||
echo
|
||||
echo "== initializing whole image =="
|
||||
$QEMU_IO -c "write -z 0 $size" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
echo
|
||||
echo "== reading whole image =="
|
||||
$QEMU_IO -s -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io
|
||||
|
@ -1,6 +1,10 @@
|
||||
QA output created by 052
|
||||
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 ==
|
||||
read 134217728/134217728 bytes at offset 0
|
||||
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
@ -58,9 +58,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
magic 0x514649fb
|
||||
version 3
|
||||
@ -220,9 +220,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
magic 0x514649fb
|
||||
version 3
|
||||
|
@ -43,7 +43,7 @@ choose_tcp_port() {
|
||||
|
||||
wait_for_tcp_port() {
|
||||
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
|
||||
done
|
||||
}
|
||||
@ -70,7 +70,7 @@ EOF
|
||||
nbd_url="nbd:127.0.0.1:$port:exportname=foo"
|
||||
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"
|
||||
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd
|
||||
|
||||
|
@ -47,6 +47,7 @@ size=128M
|
||||
echo
|
||||
echo "== Single request =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -59,6 +60,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Sequential requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -72,6 +74,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Superset overlapping requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -87,6 +90,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Subset overlapping requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -102,6 +106,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Head overlapping requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -116,6 +121,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Tail overlapping requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
@ -130,6 +136,7 @@ _cleanup_test_img
|
||||
echo
|
||||
echo "== Disjoint requests =="
|
||||
_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
|
||||
|
||||
echo
|
||||
|
@ -2,6 +2,8 @@ QA output created by 100
|
||||
|
||||
== Single request ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
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 ==
|
||||
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
|
||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
|
@ -32,9 +32,9 @@ Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of t
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
|
@ -53,6 +53,8 @@ export QEMU_IO_OPTIONS=""
|
||||
export CACHEMODE_IS_DEFAULT=true
|
||||
export QEMU_OPTIONS="-nodefaults"
|
||||
export VALGRIND_QEMU=
|
||||
export IMGKEYSECRET=
|
||||
export IMGOPTSSYNTAX=false
|
||||
|
||||
for r
|
||||
do
|
||||
@ -207,6 +209,13 @@ testlist options
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-luks)
|
||||
IMGOPTSSYNTAX=true
|
||||
IMGFMT=luks
|
||||
IMGKEYSECRET=123456
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-qed)
|
||||
IMGFMT=qed
|
||||
xpand=false
|
||||
@ -399,7 +408,11 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
|
||||
done
|
||||
|
||||
# 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_imgopts
|
||||
|
@ -123,12 +123,19 @@ _qemu_img_wrapper()
|
||||
_qemu_io_wrapper()
|
||||
{
|
||||
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
|
||||
(
|
||||
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
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
|
||||
fi
|
||||
)
|
||||
RETVAL=$?
|
||||
@ -154,6 +161,16 @@ export QEMU_IMG=_qemu_img_wrapper
|
||||
export QEMU_IO=_qemu_io_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_alias_machine=$($QEMU -machine help | \
|
||||
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
|
||||
|
@ -92,12 +92,14 @@ _filter_img_create()
|
||||
-e "s# zeroed_grain=\\(on\\|off\\)##g" \
|
||||
-e "s# subformat='[^']*'##g" \
|
||||
-e "s# adapter_type='[^']*'##g" \
|
||||
-e "s# hwversion=[^ ]*##g" \
|
||||
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \
|
||||
-e "s# block_size=[0-9]\\+##g" \
|
||||
-e "s# block_state_zero=\\(on\\|off\\)##g" \
|
||||
-e "s# log_size=[0-9]\\+##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()
|
||||
@ -115,6 +117,7 @@ _filter_img_info()
|
||||
-e "/zeroed_grain: \\(on\\|off\\)/d" \
|
||||
-e "/subformat: '[^']*'/d" \
|
||||
-e "/adapter_type: '[^']*'/d" \
|
||||
-e "/hwversion: '[^']*'/d" \
|
||||
-e "/lazy_refcounts: \\(on\\|off\\)/d" \
|
||||
-e "/block_size: [0-9]\\+/d" \
|
||||
-e "/block_state_zero: \\(on\\|off\\)/d" \
|
||||
|
@ -53,21 +53,45 @@ fi
|
||||
# make sure we have a standard umask
|
||||
umask 022
|
||||
|
||||
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"
|
||||
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
||||
DRIVER="driver=$IMGFMT"
|
||||
if [ "$IMGFMT" = "luks" ]; then
|
||||
DRIVER="$DRIVER,key-secret=keysec0"
|
||||
fi
|
||||
if [ "$IMGPROTO" = "file" ]; then
|
||||
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
|
||||
TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
|
||||
elif [ "$IMGPROTO" = "nbd" ]; then
|
||||
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
|
||||
TEST_IMG="$DRIVER,file.driver=nbd,file.host=127.0.0.1,file.port=10810"
|
||||
elif [ "$IMGPROTO" = "ssh" ]; then
|
||||
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
|
||||
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
|
||||
|
||||
_optstr_add()
|
||||
@ -108,6 +132,7 @@ _make_test_img()
|
||||
local img_name=""
|
||||
local use_backing=0
|
||||
local backing_file=""
|
||||
local object_options=""
|
||||
|
||||
if [ -n "$TEST_IMG_FILE" ]; then
|
||||
img_name=$TEST_IMG_FILE
|
||||
@ -118,6 +143,10 @@ _make_test_img()
|
||||
if [ -n "$IMGOPTS" ]; then
|
||||
optstr=$(_optstr_add "$optstr" "$IMGOPTS")
|
||||
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
|
||||
use_backing=1
|
||||
@ -135,9 +164,9 @@ _make_test_img()
|
||||
# XXX(hch): have global image options?
|
||||
(
|
||||
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
|
||||
$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
|
||||
) | _filter_img_create
|
||||
|
||||
@ -199,7 +228,13 @@ _cleanup_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' \
|
||||
-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'
|
||||
|
@ -47,7 +47,7 @@ if os.environ.get('QEMU_OPTIONS'):
|
||||
|
||||
imgfmt = os.environ.get('IMGFMT', 'raw')
|
||||
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', '.')
|
||||
cachemode = os.environ.get('CACHEMODE')
|
||||
qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE')
|
||||
@ -461,6 +461,14 @@ def verify_quorum():
|
||||
def main(supported_fmts=[], supported_oses=['linux']):
|
||||
'''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
|
||||
verbosity = 1
|
||||
verify_image_format(supported_fmts)
|
||||
|
@ -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_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_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"
|
||||
|
||||
# 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_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_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
|
||||
virtio_blk_data_plane_start(void *s) "dataplane %p"
|
||||
|
Loading…
Reference in New Issue
Block a user