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: - block: AioContext management, part 1 - qmp: forbid qmp_cont in RUN_STATE_FINISH_MIGRATE - nvme: fix copy direction in DMA reads going to CMB - file-posix: Fix block status for unaligned raw images with O_DIRECT - file-posix: Fix xfs_write_zeroes() after EOF - Documentation and iotests improvements # gpg: Signature made Mon 20 May 2019 16:12:38 BST # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (24 commits) iotests: Make 245 faster and more reliable iotests.py: Fix VM.run_job iotests.py: Let assert_qmp() accept an array block: Improve "Block node is read-only" message qemu-img.texi: Describe human-readable info output qemu-img.texi: Be specific about JSON object types iotests: Test unaligned raw images with O_DIRECT block/file-posix: Unaligned O_DIRECT block-status test-block-iothread: Test AioContext propagation for block jobs blockjob: Remove AioContext notifiers blockjob: Propagate AioContext change to all job nodes block: Add blk_set_allow_aio_context_change() block: Implement .(can_)set_aio_ctx for BlockBackend test-block-iothread: Test AioContext propagation through the tree block: Propagate AioContext change to parents block: Move recursion to bdrv_set_aio_context() block: Make bdrv_attach/detach_aio_context() static block: Add bdrv_try_set_aio_context() nvme: fix copy direction in DMA reads going to CMB iotest: fix 169: do not run qmp_cont in RUN_STATE_FINISH_MIGRATE ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -936,6 +936,20 @@ static int bdrv_child_cb_inactivate(BdrvChild *child)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
|
||||
}
|
||||
|
||||
static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
return bdrv_set_aio_context_ignore(bs, ctx, ignore);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the options and flags that a temporary snapshot should get, based on
|
||||
* the originally requested flags (the originally requested image will have
|
||||
@@ -1003,6 +1017,8 @@ const BdrvChildRole child_file = {
|
||||
.attach = bdrv_child_cb_attach,
|
||||
.detach = bdrv_child_cb_detach,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
|
||||
.set_aio_ctx = bdrv_child_cb_set_aio_ctx,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1029,6 +1045,8 @@ const BdrvChildRole child_format = {
|
||||
.attach = bdrv_child_cb_attach,
|
||||
.detach = bdrv_child_cb_detach,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
|
||||
.set_aio_ctx = bdrv_child_cb_set_aio_ctx,
|
||||
};
|
||||
|
||||
static void bdrv_backing_attach(BdrvChild *c)
|
||||
@@ -1152,6 +1170,8 @@ const BdrvChildRole child_backing = {
|
||||
.drained_end = bdrv_child_cb_drained_end,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
.update_filename = bdrv_backing_update_filename,
|
||||
.can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
|
||||
.set_aio_ctx = bdrv_child_cb_set_aio_ctx,
|
||||
};
|
||||
|
||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||
@@ -1689,6 +1709,8 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
|
||||
GSList *ignore_children, Error **errp);
|
||||
static void bdrv_child_abort_perm_update(BdrvChild *c);
|
||||
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
|
||||
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
|
||||
uint64_t *shared_perm);
|
||||
|
||||
typedef struct BlockReopenQueueEntry {
|
||||
bool prepared;
|
||||
@@ -1775,7 +1797,20 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
|
||||
if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
|
||||
!bdrv_is_writable_after_reopen(bs, q))
|
||||
{
|
||||
error_setg(errp, "Block node is read-only");
|
||||
if (!bdrv_is_writable_after_reopen(bs, NULL)) {
|
||||
error_setg(errp, "Block node is read-only");
|
||||
} else {
|
||||
uint64_t current_perms, current_shared;
|
||||
bdrv_get_cumulative_perm(bs, ¤t_perms, ¤t_shared);
|
||||
if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
|
||||
error_setg(errp, "Cannot make block node read-only, there is "
|
||||
"a writer on it");
|
||||
} else {
|
||||
error_setg(errp, "Cannot make block node read-only and create "
|
||||
"a writer on it");
|
||||
}
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -5666,10 +5701,9 @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
|
||||
g_free(ban);
|
||||
}
|
||||
|
||||
void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||
static void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||
{
|
||||
BdrvAioNotifier *baf, *baf_tmp;
|
||||
BdrvChild *child;
|
||||
|
||||
assert(!bs->walking_aio_notifiers);
|
||||
bs->walking_aio_notifiers = true;
|
||||
@@ -5688,9 +5722,6 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||
if (bs->drv && bs->drv->bdrv_detach_aio_context) {
|
||||
bs->drv->bdrv_detach_aio_context(bs);
|
||||
}
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_detach_aio_context(child->bs);
|
||||
}
|
||||
|
||||
if (bs->quiesce_counter) {
|
||||
aio_enable_external(bs->aio_context);
|
||||
@@ -5698,11 +5729,10 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
|
||||
bs->aio_context = NULL;
|
||||
}
|
||||
|
||||
void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
static void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context)
|
||||
{
|
||||
BdrvAioNotifier *ban, *ban_tmp;
|
||||
BdrvChild *child;
|
||||
|
||||
if (bs->quiesce_counter) {
|
||||
aio_disable_external(new_context);
|
||||
@@ -5710,9 +5740,6 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
bs->aio_context = new_context;
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_attach_aio_context(child->bs, new_context);
|
||||
}
|
||||
if (bs->drv && bs->drv->bdrv_attach_aio_context) {
|
||||
bs->drv->bdrv_attach_aio_context(bs, new_context);
|
||||
}
|
||||
@@ -5729,16 +5756,36 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
bs->walking_aio_notifiers = false;
|
||||
}
|
||||
|
||||
/* The caller must own the AioContext lock for the old AioContext of bs, but it
|
||||
* must not own the AioContext lock for new_context (unless new_context is
|
||||
* the same as the current context of bs). */
|
||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
/* @ignore will accumulate all visited BdrvChild object. The caller is
|
||||
* responsible for freeing the list afterwards. */
|
||||
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
||||
AioContext *new_context, GSList **ignore)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
if (bdrv_get_aio_context(bs) == new_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
if (g_slist_find(*ignore, child)) {
|
||||
continue;
|
||||
}
|
||||
*ignore = g_slist_prepend(*ignore, child);
|
||||
bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
|
||||
}
|
||||
QLIST_FOREACH(child, &bs->parents, next_parent) {
|
||||
if (g_slist_find(*ignore, child)) {
|
||||
continue;
|
||||
}
|
||||
if (child->role->set_aio_ctx) {
|
||||
*ignore = g_slist_prepend(*ignore, child);
|
||||
child->role->set_aio_ctx(child, new_context, ignore);
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_detach_aio_context(bs);
|
||||
|
||||
/* This function executes in the old AioContext so acquire the new one in
|
||||
@@ -5750,6 +5797,101 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
aio_context_release(new_context);
|
||||
}
|
||||
|
||||
/* The caller must own the AioContext lock for the old AioContext of bs, but it
|
||||
* must not own the AioContext lock for new_context (unless new_context is
|
||||
* the same as the current context of bs). */
|
||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
{
|
||||
GSList *ignore_list = NULL;
|
||||
bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
|
||||
g_slist_free(ignore_list);
|
||||
}
|
||||
|
||||
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
if (g_slist_find(*ignore, c)) {
|
||||
return true;
|
||||
}
|
||||
*ignore = g_slist_prepend(*ignore, c);
|
||||
|
||||
/* A BdrvChildRole that doesn't handle AioContext changes cannot
|
||||
* tolerate any AioContext changes */
|
||||
if (!c->role->can_set_aio_ctx) {
|
||||
char *user = bdrv_child_user_desc(c);
|
||||
error_setg(errp, "Changing iothreads is not supported by %s", user);
|
||||
g_free(user);
|
||||
return false;
|
||||
}
|
||||
if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) {
|
||||
assert(!errp || *errp);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
if (g_slist_find(*ignore, c)) {
|
||||
return true;
|
||||
}
|
||||
*ignore = g_slist_prepend(*ignore, c);
|
||||
return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp);
|
||||
}
|
||||
|
||||
/* @ignore will accumulate all visited BdrvChild object. The caller is
|
||||
* responsible for freeing the list afterwards. */
|
||||
bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
BdrvChild *c;
|
||||
|
||||
if (bdrv_get_aio_context(bs) == ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(c, &bs->parents, next_parent) {
|
||||
if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
QLIST_FOREACH(c, &bs->children, next) {
|
||||
if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
BdrvChild *ignore_child, Error **errp)
|
||||
{
|
||||
GSList *ignore;
|
||||
bool ret;
|
||||
|
||||
ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
|
||||
ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp);
|
||||
g_slist_free(ignore);
|
||||
|
||||
if (!ret) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
|
||||
bdrv_set_aio_context_ignore(bs, ctx, &ignore);
|
||||
g_slist_free(ignore);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
Error **errp)
|
||||
{
|
||||
return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp);
|
||||
}
|
||||
|
||||
void bdrv_add_aio_context_notifier(BlockDriverState *bs,
|
||||
void (*attached_aio_context)(AioContext *new_context, void *opaque),
|
||||
void (*detach_aio_context)(void *opaque), void *opaque)
|
||||
|
||||
@@ -300,13 +300,6 @@ static void backup_clean(Job *job)
|
||||
s->target = NULL;
|
||||
}
|
||||
|
||||
static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
|
||||
|
||||
blk_set_aio_context(s->target, aio_context);
|
||||
}
|
||||
|
||||
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
{
|
||||
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
|
||||
@@ -558,7 +551,6 @@ static const BlockJobDriver backup_job_driver = {
|
||||
.abort = backup_abort,
|
||||
.clean = backup_clean,
|
||||
},
|
||||
.attached_aio_context = backup_attached_aio_context,
|
||||
.drain = backup_drain,
|
||||
};
|
||||
|
||||
|
||||
+53
-2
@@ -71,6 +71,7 @@ struct BlockBackend {
|
||||
uint64_t shared_perm;
|
||||
bool disable_perm;
|
||||
|
||||
bool allow_aio_context_change;
|
||||
bool allow_write_beyond_eof;
|
||||
|
||||
NotifierList remove_bs_notifiers, insert_bs_notifiers;
|
||||
@@ -124,6 +125,11 @@ static void blk_root_drained_end(BdrvChild *child);
|
||||
static void blk_root_change_media(BdrvChild *child, bool load);
|
||||
static void blk_root_resize(BdrvChild *child);
|
||||
|
||||
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore);
|
||||
|
||||
static char *blk_root_get_parent_desc(BdrvChild *child)
|
||||
{
|
||||
BlockBackend *blk = child->opaque;
|
||||
@@ -300,6 +306,9 @@ static const BdrvChildRole child_root = {
|
||||
|
||||
.attach = blk_root_attach,
|
||||
.detach = blk_root_detach,
|
||||
|
||||
.can_set_aio_ctx = blk_root_can_set_aio_ctx,
|
||||
.set_aio_ctx = blk_root_set_aio_ctx,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1084,6 +1093,11 @@ void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow)
|
||||
blk->allow_write_beyond_eof = allow;
|
||||
}
|
||||
|
||||
void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
|
||||
{
|
||||
blk->allow_aio_context_change = allow;
|
||||
}
|
||||
|
||||
static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
size_t size)
|
||||
{
|
||||
@@ -1852,7 +1866,8 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
|
||||
return blk_get_aio_context(blk_acb->blk);
|
||||
}
|
||||
|
||||
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
||||
static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
|
||||
bool update_root_node)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
@@ -1864,10 +1879,46 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
||||
throttle_group_attach_aio_context(tgm, new_context);
|
||||
bdrv_drained_end(bs);
|
||||
}
|
||||
bdrv_set_aio_context(bs, new_context);
|
||||
if (update_root_node) {
|
||||
GSList *ignore = g_slist_prepend(NULL, blk->root);
|
||||
bdrv_set_aio_context_ignore(bs, new_context, &ignore);
|
||||
g_slist_free(ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
||||
{
|
||||
blk_do_set_aio_context(blk, new_context, true);
|
||||
}
|
||||
|
||||
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
BlockBackend *blk = child->opaque;
|
||||
|
||||
if (blk->allow_aio_context_change) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Only manually created BlockBackends that are not attached to anything
|
||||
* can change their AioContext without updating their user. */
|
||||
if (!blk->name || blk->dev) {
|
||||
/* TODO Add BB name/QOM path */
|
||||
error_setg(errp, "Cannot change iothread of active block backend");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore)
|
||||
{
|
||||
BlockBackend *blk = child->opaque;
|
||||
blk_do_set_aio_context(blk, ctx, false);
|
||||
}
|
||||
|
||||
void blk_add_aio_context_notifier(BlockBackend *blk,
|
||||
void (*attached_aio_context)(AioContext *new_context, void *opaque),
|
||||
void (*detach_aio_context)(void *opaque), void *opaque)
|
||||
|
||||
@@ -1444,9 +1444,22 @@ out:
|
||||
#ifdef CONFIG_XFS
|
||||
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||
{
|
||||
int64_t len;
|
||||
struct xfs_flock64 fl;
|
||||
int err;
|
||||
|
||||
len = lseek(s->fd, 0, SEEK_END);
|
||||
if (len < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (offset + bytes > len) {
|
||||
/* XFS_IOC_ZERO_RANGE does not increase the file length */
|
||||
if (ftruncate(s->fd, offset + bytes) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = offset;
|
||||
@@ -2475,6 +2488,8 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
off_t data = 0, hole = 0;
|
||||
int ret;
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
|
||||
|
||||
ret = fd_open(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -2500,6 +2515,20 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
|
||||
/* On a data extent, compute bytes to the end of the extent,
|
||||
* possibly including a partial sector at EOF. */
|
||||
*pnum = MIN(bytes, hole - offset);
|
||||
|
||||
/*
|
||||
* We are not allowed to return partial sectors, though, so
|
||||
* round up if necessary.
|
||||
*/
|
||||
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
|
||||
int64_t file_length = raw_getlength(bs);
|
||||
if (file_length > 0) {
|
||||
/* Ignore errors, this is just a safeguard */
|
||||
assert(hole == file_length);
|
||||
}
|
||||
*pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
|
||||
}
|
||||
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
} else {
|
||||
/* On a hole, compute bytes to the beginning of the next extent. */
|
||||
|
||||
+3
-3
@@ -769,7 +769,7 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
||||
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||
size_t size)
|
||||
{
|
||||
if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
|
||||
if (size > BDRV_REQUEST_MAX_BYTES) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
|
||||
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
|
||||
assert(bytes <= BDRV_REQUEST_MAX_BYTES);
|
||||
assert(drv->bdrv_co_readv);
|
||||
|
||||
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||
@@ -1070,7 +1070,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
|
||||
|
||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
|
||||
assert(bytes <= BDRV_REQUEST_MAX_BYTES);
|
||||
|
||||
assert(drv->bdrv_co_writev);
|
||||
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
|
||||
|
||||
+1
-9
@@ -1142,13 +1142,6 @@ static bool mirror_drained_poll(BlockJob *job)
|
||||
return !!s->in_flight;
|
||||
}
|
||||
|
||||
static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context)
|
||||
{
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
|
||||
|
||||
blk_set_aio_context(s->target, new_context);
|
||||
}
|
||||
|
||||
static void mirror_drain(BlockJob *job)
|
||||
{
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
|
||||
@@ -1178,7 +1171,6 @@ static const BlockJobDriver mirror_job_driver = {
|
||||
.complete = mirror_complete,
|
||||
},
|
||||
.drained_poll = mirror_drained_poll,
|
||||
.attached_aio_context = mirror_attached_aio_context,
|
||||
.drain = mirror_drain,
|
||||
};
|
||||
|
||||
@@ -1196,7 +1188,6 @@ static const BlockJobDriver commit_active_job_driver = {
|
||||
.complete = mirror_complete,
|
||||
},
|
||||
.drained_poll = mirror_drained_poll,
|
||||
.attached_aio_context = mirror_attached_aio_context,
|
||||
.drain = mirror_drain,
|
||||
};
|
||||
|
||||
@@ -1612,6 +1603,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
* ensure that. */
|
||||
blk_set_force_allow_inactivate(s->target);
|
||||
}
|
||||
blk_set_allow_aio_context_change(s->target, true);
|
||||
|
||||
s->replaces = g_strdup(replaces);
|
||||
s->on_source_error = on_source_error;
|
||||
|
||||
@@ -796,8 +796,9 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
return cluster_offset;
|
||||
}
|
||||
|
||||
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
|
||||
(cluster_offset >> 9);
|
||||
nb_csectors =
|
||||
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
|
||||
|
||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||
((uint64_t)nb_csectors << s->csize_shift);
|
||||
|
||||
+14
-11
@@ -1172,12 +1172,11 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
|
||||
switch (ctype) {
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
{
|
||||
int nb_csectors;
|
||||
nb_csectors = ((l2_entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
qcow2_free_clusters(bs,
|
||||
(l2_entry & s->cluster_offset_mask) & ~511,
|
||||
nb_csectors * 512, type);
|
||||
int64_t offset = (l2_entry & s->cluster_offset_mask)
|
||||
& QCOW2_COMPRESSED_SECTOR_MASK;
|
||||
int size = QCOW2_COMPRESSED_SECTOR_SIZE *
|
||||
(((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
|
||||
qcow2_free_clusters(bs, offset, size, type);
|
||||
}
|
||||
break;
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
@@ -1317,9 +1316,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
nb_csectors = ((entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
if (addend != 0) {
|
||||
uint64_t coffset = (entry & s->cluster_offset_mask)
|
||||
& QCOW2_COMPRESSED_SECTOR_MASK;
|
||||
ret = update_refcount(
|
||||
bs, (entry & s->cluster_offset_mask) & ~511,
|
||||
nb_csectors * 512, abs(addend), addend < 0,
|
||||
bs, coffset,
|
||||
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
|
||||
abs(addend), addend < 0,
|
||||
QCOW2_DISCARD_SNAPSHOT);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -1635,9 +1637,10 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
nb_csectors = ((l2_entry >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
l2_entry &= s->cluster_offset_mask;
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res,
|
||||
refcount_table, refcount_table_size,
|
||||
l2_entry & ~511, nb_csectors * 512);
|
||||
ret = qcow2_inc_refcounts_imrt(
|
||||
bs, res, refcount_table, refcount_table_size,
|
||||
l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
|
||||
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+2
-1
@@ -4187,7 +4187,8 @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
|
||||
|
||||
coffset = file_cluster_offset & s->cluster_offset_mask;
|
||||
nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
|
||||
csize = nb_csectors * 512 - (coffset & 511);
|
||||
csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||
(coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
|
||||
|
||||
buf = g_try_malloc(csize);
|
||||
if (!buf) {
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
#define MIN_CLUSTER_BITS 9
|
||||
#define MAX_CLUSTER_BITS 21
|
||||
|
||||
/* Defined in the qcow2 spec (compressed cluster descriptor) */
|
||||
#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
|
||||
#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1))
|
||||
|
||||
/* Must be at least 2 to cover COW */
|
||||
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
|
||||
|
||||
|
||||
+36
-41
@@ -81,10 +81,6 @@ BlockJob *block_job_get(const char *id)
|
||||
}
|
||||
}
|
||||
|
||||
static void block_job_attached_aio_context(AioContext *new_context,
|
||||
void *opaque);
|
||||
static void block_job_detach_aio_context(void *opaque);
|
||||
|
||||
void block_job_free(Job *job)
|
||||
{
|
||||
BlockJob *bjob = container_of(job, BlockJob, job);
|
||||
@@ -92,28 +88,10 @@ void block_job_free(Job *job)
|
||||
|
||||
bs->job = NULL;
|
||||
block_job_remove_all_bdrv(bjob);
|
||||
blk_remove_aio_context_notifier(bjob->blk,
|
||||
block_job_attached_aio_context,
|
||||
block_job_detach_aio_context, bjob);
|
||||
blk_unref(bjob->blk);
|
||||
error_free(bjob->blocker);
|
||||
}
|
||||
|
||||
static void block_job_attached_aio_context(AioContext *new_context,
|
||||
void *opaque)
|
||||
{
|
||||
BlockJob *job = opaque;
|
||||
const JobDriver *drv = job->job.driver;
|
||||
BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
|
||||
|
||||
job->job.aio_context = new_context;
|
||||
if (bjdrv->attached_aio_context) {
|
||||
bjdrv->attached_aio_context(job, new_context);
|
||||
}
|
||||
|
||||
job_resume(&job->job);
|
||||
}
|
||||
|
||||
void block_job_drain(Job *job)
|
||||
{
|
||||
BlockJob *bjob = container_of(job, BlockJob, job);
|
||||
@@ -126,23 +104,6 @@ void block_job_drain(Job *job)
|
||||
}
|
||||
}
|
||||
|
||||
static void block_job_detach_aio_context(void *opaque)
|
||||
{
|
||||
BlockJob *job = opaque;
|
||||
|
||||
/* In case the job terminates during aio_poll()... */
|
||||
job_ref(&job->job);
|
||||
|
||||
job_pause(&job->job);
|
||||
|
||||
while (!job->job.paused && !job_is_completed(&job->job)) {
|
||||
job_drain(&job->job);
|
||||
}
|
||||
|
||||
job->job.aio_context = NULL;
|
||||
job_unref(&job->job);
|
||||
}
|
||||
|
||||
static char *child_job_get_parent_desc(BdrvChild *c)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
@@ -183,11 +144,46 @@ static void child_job_drained_end(BdrvChild *c)
|
||||
job_resume(&job->job);
|
||||
}
|
||||
|
||||
static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore, Error **errp)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
GSList *l;
|
||||
|
||||
for (l = job->nodes; l; l = l->next) {
|
||||
BdrvChild *sibling = l->data;
|
||||
if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
GSList *l;
|
||||
|
||||
for (l = job->nodes; l; l = l->next) {
|
||||
BdrvChild *sibling = l->data;
|
||||
if (g_slist_find(*ignore, sibling)) {
|
||||
continue;
|
||||
}
|
||||
*ignore = g_slist_prepend(*ignore, sibling);
|
||||
bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
|
||||
}
|
||||
|
||||
job->job.aio_context = ctx;
|
||||
}
|
||||
|
||||
static const BdrvChildRole child_job = {
|
||||
.get_parent_desc = child_job_get_parent_desc,
|
||||
.drained_begin = child_job_drained_begin,
|
||||
.drained_poll = child_job_drained_poll,
|
||||
.drained_end = child_job_drained_end,
|
||||
.can_set_aio_ctx = child_job_can_set_aio_ctx,
|
||||
.set_aio_ctx = child_job_set_aio_ctx,
|
||||
.stay_at_node = true,
|
||||
};
|
||||
|
||||
@@ -438,8 +434,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
|
||||
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
|
||||
|
||||
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
|
||||
block_job_detach_aio_context, job);
|
||||
blk_set_allow_aio_context_change(blk, true);
|
||||
|
||||
/* Only set speed when necessary to avoid NotSupported error */
|
||||
if (speed != 0) {
|
||||
|
||||
+1
-1
@@ -238,7 +238,7 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
|
||||
}
|
||||
qemu_sglist_destroy(&qsg);
|
||||
} else {
|
||||
if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
|
||||
if (unlikely(qemu_iovec_from_buf(&iov, 0, ptr, len) != len)) {
|
||||
trace_nvme_err_invalid_dma();
|
||||
status = NVME_INVALID_FIELD | NVME_DNR;
|
||||
}
|
||||
|
||||
@@ -586,6 +586,16 @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
|
||||
* This function must be called with iothread lock held.
|
||||
*/
|
||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
|
||||
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
||||
AioContext *new_context, GSList **ignore);
|
||||
int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
Error **errp);
|
||||
int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
BdrvChild *ignore_child, Error **errp);
|
||||
bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
|
||||
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
|
||||
|
||||
|
||||
@@ -691,6 +691,10 @@ struct BdrvChildRole {
|
||||
* can update its reference. */
|
||||
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
|
||||
const char *filename, Error **errp);
|
||||
|
||||
bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
|
||||
GSList **ignore, Error **errp);
|
||||
void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
|
||||
};
|
||||
|
||||
extern const BdrvChildRole child_file;
|
||||
@@ -962,27 +966,6 @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix,
|
||||
void bdrv_add_before_write_notifier(BlockDriverState *bs,
|
||||
NotifierWithReturn *notifier);
|
||||
|
||||
/**
|
||||
* bdrv_detach_aio_context:
|
||||
*
|
||||
* May be called from .bdrv_detach_aio_context() to detach children from the
|
||||
* current #AioContext. This is only needed by block drivers that manage their
|
||||
* own children. Both ->file and ->backing are automatically handled and
|
||||
* block drivers should not call this function on them explicitly.
|
||||
*/
|
||||
void bdrv_detach_aio_context(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_attach_aio_context:
|
||||
*
|
||||
* May be called from .bdrv_attach_aio_context() to attach children to the new
|
||||
* #AioContext. This is only needed by block drivers that manage their own
|
||||
* children. Both ->file and ->backing are automatically handled and block
|
||||
* drivers should not call this function on them explicitly.
|
||||
*/
|
||||
void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context);
|
||||
|
||||
/**
|
||||
* bdrv_add_aio_context_notifier:
|
||||
*
|
||||
|
||||
@@ -103,6 +103,7 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
|
||||
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
|
||||
|
||||
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
|
||||
void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow);
|
||||
void blk_iostatus_enable(BlockBackend *blk);
|
||||
bool blk_iostatus_is_enabled(const BlockBackend *blk);
|
||||
BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
|
||||
|
||||
+49
-3
@@ -230,6 +230,7 @@ overridden with a pattern byte specified by @var{pattern}.
|
||||
|
||||
Perform a consistency check on the disk image @var{filename}. The command can
|
||||
output in the format @var{ofmt} which is either @code{human} or @code{json}.
|
||||
The JSON output is an object of QAPI type @code{ImageCheck}.
|
||||
|
||||
If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
|
||||
during the check. @code{-r leaks} repairs only cluster leaks, whereas
|
||||
@@ -406,8 +407,7 @@ The size syntax is similar to dd(1)'s size syntax.
|
||||
Give information about the disk image @var{filename}. Use it in
|
||||
particular to know the size reserved on disk which can be different
|
||||
from the displayed size. If VM snapshots are stored in the disk image,
|
||||
they are displayed too. The command can output in the format @var{ofmt}
|
||||
which is either @code{human} or @code{json}.
|
||||
they are displayed too.
|
||||
|
||||
If a disk image has a backing file chain, information about each disk image in
|
||||
the chain can be recursively enumerated by using the option @code{--backing-chain}.
|
||||
@@ -424,6 +424,51 @@ To enumerate information about each disk image in the above chain, starting from
|
||||
qemu-img info --backing-chain snap2.qcow2
|
||||
@end example
|
||||
|
||||
The command can output in the format @var{ofmt} which is either @code{human} or
|
||||
@code{json}. The JSON output is an object of QAPI type @code{ImageInfo}; with
|
||||
@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
|
||||
|
||||
@code{--output=human} reports the following information (for every image in the
|
||||
chain):
|
||||
@table @var
|
||||
@item image
|
||||
The image file name
|
||||
|
||||
@item file format
|
||||
The image format
|
||||
|
||||
@item virtual size
|
||||
The size of the guest disk
|
||||
|
||||
@item disk size
|
||||
How much space the image file occupies on the host file system (may be shown as
|
||||
0 if this information is unavailable, e.g. because there is no file system)
|
||||
|
||||
@item cluster_size
|
||||
Cluster size of the image format, if applicable
|
||||
|
||||
@item encrypted
|
||||
Whether the image is encrypted (only present if so)
|
||||
|
||||
@item cleanly shut down
|
||||
This is shown as @code{no} if the image is dirty and will have to be
|
||||
auto-repaired the next time it is opened in qemu.
|
||||
|
||||
@item backing file
|
||||
The backing file name, if present
|
||||
|
||||
@item backing file format
|
||||
The format of the backing file, if the image enforces it
|
||||
|
||||
@item Snapshot list
|
||||
A list of all internal snapshots
|
||||
|
||||
@item Format specific information
|
||||
Further information whose structure depends on the image format. This section
|
||||
is a textual representation of the respective @code{ImageInfoSpecific*} QAPI
|
||||
object (e.g. @code{ImageInfoSpecificQCow2} for qcow2 images).
|
||||
@end table
|
||||
|
||||
@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
|
||||
|
||||
Dump the metadata of image @var{filename} and its backing file chain.
|
||||
@@ -485,7 +530,8 @@ Calculate the file size required for a new image. This information can be used
|
||||
to size logical volumes or SAN LUNs appropriately for the image that will be
|
||||
placed in them. The values reported are guaranteed to be large enough to fit
|
||||
the image. The command can output in the format @var{ofmt} which is either
|
||||
@code{human} or @code{json}.
|
||||
@code{human} or @code{json}. The JSON output is an object of QAPI type
|
||||
@code{BlockMeasureInfo}.
|
||||
|
||||
If the size @var{N} is given then act as if creating a new empty image file
|
||||
using @command{qemu-img create}. If @var{filename} is given then act as if
|
||||
|
||||
+3
-4
@@ -538,7 +538,7 @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (bytes >> 9 > BDRV_REQUEST_MAX_SECTORS) {
|
||||
if (bytes > BDRV_REQUEST_MAX_BYTES) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
@@ -1781,10 +1781,9 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
|
||||
if (bytes < 0) {
|
||||
print_cvtnum_err(bytes, argv[optind]);
|
||||
return bytes;
|
||||
} else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
|
||||
} else if (bytes > BDRV_REQUEST_MAX_BYTES) {
|
||||
printf("length cannot exceed %"PRIu64", given %s\n",
|
||||
(uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
|
||||
argv[optind]);
|
||||
(uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,9 @@ void qmp_cont(Error **errp)
|
||||
return;
|
||||
} else if (runstate_check(RUN_STATE_SUSPENDED)) {
|
||||
return;
|
||||
} else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
|
||||
error_setg(errp, "Migration is not finalized yet");
|
||||
return;
|
||||
}
|
||||
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
|
||||
@@ -102,12 +102,17 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
|
||||
event = self.vm_a.event_wait('MIGRATION')
|
||||
if event['data']['status'] == 'completed':
|
||||
break
|
||||
while True:
|
||||
result = self.vm_a.qmp('query-status')
|
||||
if (result['return']['status'] == 'postmigrate'):
|
||||
break
|
||||
|
||||
# test that bitmap is still here
|
||||
removed = (not migrate_bitmaps) and persistent
|
||||
self.check_bitmap(self.vm_a, False if removed else sha256)
|
||||
|
||||
self.vm_a.qmp('cont')
|
||||
result = self.vm_a.qmp('cont')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# test that bitmap is still here after invalidation
|
||||
self.check_bitmap(self.vm_a, sha256)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img vs. unaligned images
|
||||
# (See also 253, which is the O_DIRECT version)
|
||||
#
|
||||
# Copyright (C) 2018-2019 Red Hat, Inc.
|
||||
#
|
||||
@@ -37,6 +38,9 @@ _supported_fmt raw
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
_default_cache_mode writeback
|
||||
_supported_cache_modes writeback writethrough unsafe
|
||||
|
||||
echo
|
||||
echo "=== Check mapping of unaligned raw image ==="
|
||||
echo
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user