mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
+35
-81
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+33
-18
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
+23
-17
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+8
-2
@@ -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 */
|
||||
|
||||
+23
-17
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
+253
-261
File diff suppressed because it is too large
Load Diff
+8
-11
@@ -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__
|
||||
|
||||
+21
-36
@@ -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) {
|
||||
|
||||
+7
-4
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
+3
-34
@@ -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,
|
||||
|
||||
+3
-2
@@ -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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+61
-15
@@ -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;
|
||||
|
||||
+3
-9
@@ -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) {
|
||||
|
||||
+76
-18
@@ -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,
|
||||
};
|
||||
|
||||
+8
-7
@@ -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
|
||||
|
||||
+4
-17
@@ -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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user