mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
# gpg: Signature made Tue 13 Jan 2015 13:48:06 GMT using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/block-pull-request: (38 commits) NVMe: Set correct VS Value for 1.1 Compliant Controllers MAINTAINERS: Add migration/block* to block subsystem MAINTAINERS: Update email addresses for Chrysostomos Nanakos nvme: Fix get/set number of queues feature ide: Implement VPD response for ATAPI block: Split BLOCK_OP_TYPE_COMMIT to BLOCK_OP_TYPE_COMMIT_{SOURCE, TARGET} block: limited request size in write zeroes unsupported path coroutine: try harder not to delete coroutines coroutine: drop qemu_coroutine_adjust_pool_size coroutine: rewrite pool to avoid mutex QSLIST: add lock-free operations test-coroutine: avoid overflow on 32-bit systems qemu-thread: add per-thread atexit functions coroutine-ucontext: use __thread qemu-iotests: Add supported os parameter for python tests qemu-iotests: Add "_supported_os Linux" to 058 qemu-iotests: Replace "/bin/true" with "true" .gitignore: Ignore generated "common.env" libqos: Convert malloc-pc allocator to a generic allocator migration/block: fix pending() return value ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -109,3 +109,4 @@ cscope.*
|
||||
tags
|
||||
TAGS
|
||||
*~
|
||||
/tests/qemu-iotests/common.env
|
||||
|
||||
+1
-1
@@ -757,6 +757,7 @@ F: aio-*.c
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: migration/block*
|
||||
F: qemu-img*
|
||||
F: qemu-io*
|
||||
F: tests/image-fuzzer/
|
||||
@@ -1105,7 +1106,6 @@ S: Supported
|
||||
F: block/ssh.c
|
||||
|
||||
ARCHIPELAGO
|
||||
M: Chrysostomos Nanakos <cnanakos@grnet.gr>
|
||||
M: Chrysostomos Nanakos <chris@include.gr>
|
||||
S: Maintained
|
||||
F: block/archipelago.c
|
||||
|
||||
@@ -44,10 +44,12 @@ struct QEMUBH {
|
||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh;
|
||||
bh = g_new0(QEMUBH, 1);
|
||||
bh->ctx = ctx;
|
||||
bh->cb = cb;
|
||||
bh->opaque = opaque;
|
||||
bh = g_new(QEMUBH, 1);
|
||||
*bh = (QEMUBH){
|
||||
.ctx = ctx,
|
||||
.cb = cb,
|
||||
.opaque = opaque,
|
||||
};
|
||||
qemu_mutex_lock(&ctx->bh_lock);
|
||||
bh->next = ctx->first_bh;
|
||||
/* Make sure that the members are ready before putting bh into list */
|
||||
@@ -300,6 +302,7 @@ AioContext *aio_context_new(Error **errp)
|
||||
error_setg_errno(errp, -ret, "Failed to initialize event notifier");
|
||||
return NULL;
|
||||
}
|
||||
g_source_set_can_recurse(&ctx->source, true);
|
||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||
(EventNotifierHandler *)
|
||||
event_notifier_test_and_clear);
|
||||
|
||||
@@ -97,6 +97,10 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
|
||||
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||
QLIST_HEAD_INITIALIZER(bdrv_drivers);
|
||||
|
||||
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors);
|
||||
/* If non-zero, use only whitelisted block drivers */
|
||||
static int use_bdrv_whitelist;
|
||||
|
||||
@@ -303,15 +307,32 @@ void path_combine(char *dest, int dest_size,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz)
|
||||
void bdrv_get_full_backing_filename_from_filename(const char *backed,
|
||||
const char *backing,
|
||||
char *dest, size_t sz,
|
||||
Error **errp)
|
||||
{
|
||||
if (bs->backing_file[0] == '\0' || path_has_protocol(bs->backing_file)) {
|
||||
pstrcpy(dest, sz, bs->backing_file);
|
||||
if (backing[0] == '\0' || path_has_protocol(backing) ||
|
||||
path_is_absolute(backing))
|
||||
{
|
||||
pstrcpy(dest, sz, backing);
|
||||
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
|
||||
error_setg(errp, "Cannot use relative backing file names for '%s'",
|
||||
backed);
|
||||
} else {
|
||||
path_combine(dest, sz, bs->filename, bs->backing_file);
|
||||
path_combine(dest, sz, backed, backing);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
|
||||
Error **errp)
|
||||
{
|
||||
char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
|
||||
|
||||
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
|
||||
dest, sz, errp);
|
||||
}
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
/* Block drivers without coroutine functions need emulation */
|
||||
@@ -1179,7 +1200,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||
|
||||
bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
|
||||
/* Otherwise we won't be able to commit due to check in bdrv_commit */
|
||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
|
||||
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
|
||||
bs->backing_blocker);
|
||||
out:
|
||||
bdrv_refresh_limits(bs, NULL);
|
||||
@@ -1217,7 +1238,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
QDECREF(options);
|
||||
goto free_exit;
|
||||
} else {
|
||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
|
||||
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
QDECREF(options);
|
||||
goto free_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bs->drv || !bs->drv->supports_backing) {
|
||||
@@ -2188,8 +2216,8 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
|
||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
|
||||
bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET, NULL)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -3034,18 +3062,16 @@ 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 (max_nb_sectors > 0) {
|
||||
if (nb_sectors < max_nb_sectors) {
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||
} else if (max_nb_sectors > 0) {
|
||||
QEMUIOVector local_qiov;
|
||||
size_t local_sectors;
|
||||
|
||||
max_nb_sectors = MIN(max_nb_sectors, SIZE_MAX / BDRV_SECTOR_BITS);
|
||||
local_sectors = MIN(max_nb_sectors, nb_sectors);
|
||||
|
||||
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||
qemu_iovec_concat(&local_qiov, qiov, 0,
|
||||
local_sectors * BDRV_SECTOR_SIZE);
|
||||
max_nb_sectors * BDRV_SECTOR_SIZE);
|
||||
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, local_sectors,
|
||||
ret = drv->bdrv_co_readv(bs, sector_num, max_nb_sectors,
|
||||
&local_qiov);
|
||||
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
@@ -3218,6 +3244,9 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
|
||||
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_DEFAULT);
|
||||
num = MIN(num, max_xfer_len);
|
||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||
if (iov.iov_base == NULL) {
|
||||
iov.iov_base = qemu_try_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
||||
@@ -3234,7 +3263,7 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
/* Keep bounce buffer around if it is big enough for all
|
||||
* all future requests.
|
||||
*/
|
||||
if (num < max_write_zeroes) {
|
||||
if (num < max_xfer_len) {
|
||||
qemu_vfree(iov.iov_base);
|
||||
iov.iov_base = NULL;
|
||||
}
|
||||
@@ -5389,8 +5418,20 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
|
||||
hbitmap_iter_init(hbi, bitmap->bitmap, 0);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors)
|
||||
{
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors)
|
||||
{
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
}
|
||||
|
||||
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
@@ -5398,7 +5439,8 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
|
||||
static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int nr_sectors)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
@@ -5637,16 +5679,26 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
if (size == -1) {
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs;
|
||||
char *full_backing = g_new0(char, PATH_MAX);
|
||||
int64_t size;
|
||||
int back_flags;
|
||||
|
||||
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||
full_backing, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
g_free(full_backing);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* backing files always opened read-only */
|
||||
back_flags =
|
||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
|
||||
bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, back_flags,
|
||||
ret = bdrv_open(&bs, full_backing, NULL, NULL, back_flags,
|
||||
backing_drv, &local_err);
|
||||
g_free(full_backing);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -360,6 +360,7 @@ static void coroutine_fn backup_run(void *opaque)
|
||||
hbitmap_free(job->bitmap);
|
||||
|
||||
bdrv_iostatus_disable(target);
|
||||
bdrv_op_unblock_all(target, job->common.blocker);
|
||||
|
||||
data = g_malloc(sizeof(*data));
|
||||
data->ret = ret;
|
||||
@@ -379,6 +380,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
assert(target);
|
||||
assert(cb);
|
||||
|
||||
if (bs == target) {
|
||||
error_setg(errp, "Source and target cannot be the same");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
|
||||
on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
|
||||
!bdrv_iostatus_is_enabled(bs)) {
|
||||
@@ -386,6 +392,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_setg(errp, "Device is not inserted: %s",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bdrv_is_inserted(target)) {
|
||||
error_setg(errp, "Device is not inserted: %s",
|
||||
bdrv_get_device_name(target));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = bdrv_getlength(bs);
|
||||
if (len < 0) {
|
||||
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
||||
@@ -399,6 +425,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_op_block_all(target, job->common.blocker);
|
||||
|
||||
job->on_source_error = on_source_error;
|
||||
job->on_target_error = on_target_error;
|
||||
job->target = target;
|
||||
|
||||
@@ -260,9 +260,6 @@ int blk_attach_dev(BlockBackend *blk, void *dev)
|
||||
blk_ref(blk);
|
||||
blk->dev = dev;
|
||||
bdrv_iostatus_reset(blk->bs);
|
||||
|
||||
/* We're expecting I/O from the device so bump up coroutine pool size */
|
||||
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -290,7 +287,6 @@ void blk_detach_dev(BlockBackend *blk, void *dev)
|
||||
blk->dev_ops = NULL;
|
||||
blk->dev_opaque = NULL;
|
||||
bdrv_set_guest_block_size(blk->bs, 512);
|
||||
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
|
||||
blk_unref(blk);
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -128,7 +128,8 @@ static void mirror_write_complete(void *opaque, int ret)
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
action = mirror_error_action(s, false, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -145,7 +146,8 @@ static void mirror_read_complete(void *opaque, int ret)
|
||||
BlockDriverState *source = s->common.bs;
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
|
||||
bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
|
||||
op->nb_sectors);
|
||||
action = mirror_error_action(s, true, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@@ -286,7 +288,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
next_sector += sectors_per_chunk;
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(source, sector_num, nb_sectors);
|
||||
bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
|
||||
nb_sectors);
|
||||
|
||||
/* Copy the dirty cluster. */
|
||||
s->in_flight++;
|
||||
@@ -442,7 +445,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
assert(n > 0);
|
||||
if (ret == 1) {
|
||||
bdrv_set_dirty(bs, sector_num, n);
|
||||
bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
|
||||
sector_num = next;
|
||||
} else {
|
||||
sector_num += n;
|
||||
|
||||
+6
-1
@@ -214,7 +214,12 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
info->backing_filename = g_strdup(backing_filename);
|
||||
info->has_backing_filename = true;
|
||||
bdrv_get_full_backing_filename(bs, backing_filename2,
|
||||
sizeof(backing_filename2));
|
||||
sizeof(backing_filename2), &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
qapi_free_ImageInfo(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(backing_filename, backing_filename2) != 0) {
|
||||
info->full_backing_filename =
|
||||
|
||||
+12
-1
@@ -1891,8 +1891,19 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
if (backing_file) {
|
||||
BlockDriverState *bs = NULL;
|
||||
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||
char *full_backing = g_new0(char, PATH_MAX);
|
||||
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
|
||||
full_backing, PATH_MAX,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
g_free(full_backing);
|
||||
error_propagate(errp, local_err);
|
||||
ret = -ENOENT;
|
||||
goto exit;
|
||||
}
|
||||
ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, NULL,
|
||||
errp);
|
||||
g_free(full_backing);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
+138
-1
@@ -1559,6 +1559,79 @@ static void drive_backup_clean(BlkTransactionState *common)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct BlockdevBackupState {
|
||||
BlkTransactionState common;
|
||||
BlockDriverState *bs;
|
||||
BlockJob *job;
|
||||
AioContext *aio_context;
|
||||
} BlockdevBackupState;
|
||||
|
||||
static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
BlockdevBackup *backup;
|
||||
BlockDriverState *bs, *target;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
|
||||
backup = common->action->blockdev_backup;
|
||||
|
||||
bs = bdrv_find(backup->device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
|
||||
return;
|
||||
}
|
||||
|
||||
target = bdrv_find(backup->target);
|
||||
if (!target) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target);
|
||||
return;
|
||||
}
|
||||
|
||||
/* AioContext is released in .clean() */
|
||||
state->aio_context = bdrv_get_aio_context(bs);
|
||||
if (state->aio_context != bdrv_get_aio_context(target)) {
|
||||
state->aio_context = NULL;
|
||||
error_setg(errp, "Backup between two IO threads is not implemented");
|
||||
return;
|
||||
}
|
||||
aio_context_acquire(state->aio_context);
|
||||
|
||||
qmp_blockdev_backup(backup->device, backup->target,
|
||||
backup->sync,
|
||||
backup->has_speed, backup->speed,
|
||||
backup->has_on_source_error, backup->on_source_error,
|
||||
backup->has_on_target_error, backup->on_target_error,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
state->bs = bs;
|
||||
state->job = state->bs->job;
|
||||
}
|
||||
|
||||
static void blockdev_backup_abort(BlkTransactionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
BlockDriverState *bs = state->bs;
|
||||
|
||||
/* Only cancel if it's the job we started */
|
||||
if (bs && bs->job && bs->job == state->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
}
|
||||
}
|
||||
|
||||
static void blockdev_backup_clean(BlkTransactionState *common)
|
||||
{
|
||||
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
|
||||
|
||||
if (state->aio_context) {
|
||||
aio_context_release(state->aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void abort_prepare(BlkTransactionState *common, Error **errp)
|
||||
{
|
||||
error_setg(errp, "Transaction aborted using Abort action");
|
||||
@@ -1582,6 +1655,12 @@ static const BdrvActionOps actions[] = {
|
||||
.abort = drive_backup_abort,
|
||||
.clean = drive_backup_clean,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP] = {
|
||||
.instance_size = sizeof(BlockdevBackupState),
|
||||
.prepare = blockdev_backup_prepare,
|
||||
.abort = blockdev_backup_abort,
|
||||
.clean = blockdev_backup_clean,
|
||||
},
|
||||
[TRANSACTION_ACTION_KIND_ABORT] = {
|
||||
.instance_size = sizeof(BlkTransactionState),
|
||||
.prepare = abort_prepare,
|
||||
@@ -2139,7 +2218,7 @@ void qmp_block_commit(const char *device,
|
||||
/* drain all i/o before commits */
|
||||
bdrv_drain_all();
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2172,6 +2251,10 @@ void qmp_block_commit(const char *device,
|
||||
|
||||
assert(bdrv_get_aio_context(base_bs) == aio_context);
|
||||
|
||||
if (bdrv_op_is_blocked(base_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Do not allow attempts to commit an image into itself */
|
||||
if (top_bs == base_bs) {
|
||||
error_setg(errp, "cannot commit an image into itself");
|
||||
@@ -2240,6 +2323,8 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
/* Although backup_run has this check too, we need to use bs->drv below, so
|
||||
* do an early check redundantly. */
|
||||
if (!bdrv_is_inserted(bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
goto out;
|
||||
@@ -2256,6 +2341,7 @@ void qmp_drive_backup(const char *device, const char *target,
|
||||
}
|
||||
}
|
||||
|
||||
/* Early check to avoid creating target */
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
||||
goto out;
|
||||
}
|
||||
@@ -2323,6 +2409,57 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
|
||||
return bdrv_named_nodes_list();
|
||||
}
|
||||
|
||||
void qmp_blockdev_backup(const char *device, const char *target,
|
||||
enum MirrorSyncMode sync,
|
||||
bool has_speed, int64_t speed,
|
||||
bool has_on_source_error,
|
||||
BlockdevOnError on_source_error,
|
||||
bool has_on_target_error,
|
||||
BlockdevOnError on_target_error,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *target_bs;
|
||||
Error *local_err = NULL;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (!has_speed) {
|
||||
speed = 0;
|
||||
}
|
||||
if (!has_on_source_error) {
|
||||
on_source_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
if (!has_on_target_error) {
|
||||
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
}
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
target_bs = bdrv_find(target);
|
||||
if (!target_bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, target);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bdrv_ref(target_bs);
|
||||
bdrv_set_aio_context(target_bs, aio_context);
|
||||
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
|
||||
block_job_cb, bs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
bdrv_unref(target_bs);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
||||
|
||||
void qmp_drive_mirror(const char *device, const char *target,
|
||||
|
||||
+19
-50
@@ -25,7 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <ucontext.h>
|
||||
#include "qemu-common.h"
|
||||
#include "block/coroutine_int.h"
|
||||
@@ -48,15 +47,8 @@ typedef struct {
|
||||
/**
|
||||
* Per-thread coroutine bookkeeping
|
||||
*/
|
||||
typedef struct {
|
||||
/** Currently executing coroutine */
|
||||
Coroutine *current;
|
||||
|
||||
/** The default coroutine */
|
||||
CoroutineUContext leader;
|
||||
} CoroutineThreadState;
|
||||
|
||||
static pthread_key_t thread_state_key;
|
||||
static __thread CoroutineUContext leader;
|
||||
static __thread Coroutine *current;
|
||||
|
||||
/*
|
||||
* va_args to makecontext() must be type 'int', so passing
|
||||
@@ -68,36 +60,6 @@ union cc_arg {
|
||||
int i[2];
|
||||
};
|
||||
|
||||
static CoroutineThreadState *coroutine_get_thread_state(void)
|
||||
{
|
||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
||||
|
||||
if (!s) {
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->current = &s->leader.base;
|
||||
pthread_setspecific(thread_state_key, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static void qemu_coroutine_thread_cleanup(void *opaque)
|
||||
{
|
||||
CoroutineThreadState *s = opaque;
|
||||
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) coroutine_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void coroutine_trampoline(int i0, int i1)
|
||||
{
|
||||
union cc_arg arg;
|
||||
@@ -193,15 +155,23 @@ void qemu_coroutine_delete(Coroutine *co_)
|
||||
g_free(co);
|
||||
}
|
||||
|
||||
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
/* This function is marked noinline to prevent GCC from inlining it
|
||||
* into coroutine_trampoline(). If we allow it to do that then it
|
||||
* hoists the code to get the address of the TLS variable "current"
|
||||
* out of the while() loop. This is an invalid transformation because
|
||||
* the sigsetjmp() call may be called when running thread A but
|
||||
* return in thread B, and so we might be in a different thread
|
||||
* context each time round the loop.
|
||||
*/
|
||||
CoroutineAction __attribute__((noinline))
|
||||
qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
CoroutineAction action)
|
||||
{
|
||||
CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
|
||||
CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
int ret;
|
||||
|
||||
s->current = to_;
|
||||
current = to_;
|
||||
|
||||
ret = sigsetjmp(from->env, 0);
|
||||
if (ret == 0) {
|
||||
@@ -212,14 +182,13 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||
|
||||
Coroutine *qemu_coroutine_self(void)
|
||||
{
|
||||
CoroutineThreadState *s = coroutine_get_thread_state();
|
||||
|
||||
return s->current;
|
||||
if (!current) {
|
||||
current = &leader.base;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
bool qemu_in_coroutine(void)
|
||||
{
|
||||
CoroutineThreadState *s = pthread_getspecific(thread_state_key);
|
||||
|
||||
return s && s->current->caller;
|
||||
return current && current->caller;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
|
||||
|
||||
+5
-3
@@ -476,7 +476,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||
|
||||
switch (dw10) {
|
||||
case NVME_NUMBER_OF_QUEUES:
|
||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
||||
req->cqe.result =
|
||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||
break;
|
||||
default:
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
@@ -490,7 +491,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
|
||||
|
||||
switch (dw10) {
|
||||
case NVME_NUMBER_OF_QUEUES:
|
||||
req->cqe.result = cpu_to_le32(n->num_queues);
|
||||
req->cqe.result =
|
||||
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
|
||||
break;
|
||||
default:
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
@@ -813,7 +815,7 @@ static int nvme_init(PCIDevice *pci_dev)
|
||||
NVME_CAP_SET_CSS(n->bar.cap, 1);
|
||||
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
|
||||
|
||||
n->bar.vs = 0x00010001;
|
||||
n->bar.vs = 0x00010100;
|
||||
n->bar.intmc = n->bar.intms = 0;
|
||||
|
||||
for (i = 0; i < n->num_namespaces; i++) {
|
||||
|
||||
+99
-12
@@ -621,20 +621,107 @@ static void cmd_request_sense(IDEState *s, uint8_t *buf)
|
||||
|
||||
static void cmd_inquiry(IDEState *s, uint8_t *buf)
|
||||
{
|
||||
uint8_t page_code = buf[2];
|
||||
int max_len = buf[4];
|
||||
|
||||
buf[0] = 0x05; /* CD-ROM */
|
||||
buf[1] = 0x80; /* removable */
|
||||
buf[2] = 0x00; /* ISO */
|
||||
buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
|
||||
buf[4] = 31; /* additional length */
|
||||
buf[5] = 0; /* reserved */
|
||||
buf[6] = 0; /* reserved */
|
||||
buf[7] = 0; /* reserved */
|
||||
padstr8(buf + 8, 8, "QEMU");
|
||||
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
||||
padstr8(buf + 32, 4, s->version);
|
||||
ide_atapi_cmd_reply(s, 36, max_len);
|
||||
unsigned idx = 0;
|
||||
unsigned size_idx;
|
||||
unsigned preamble_len;
|
||||
|
||||
/* If the EVPD (Enable Vital Product Data) bit is set in byte 1,
|
||||
* we are being asked for a specific page of info indicated by byte 2. */
|
||||
if (buf[1] & 0x01) {
|
||||
preamble_len = 4;
|
||||
size_idx = 3;
|
||||
|
||||
buf[idx++] = 0x05; /* CD-ROM */
|
||||
buf[idx++] = page_code; /* Page Code */
|
||||
buf[idx++] = 0x00; /* reserved */
|
||||
idx++; /* length (set later) */
|
||||
|
||||
switch (page_code) {
|
||||
case 0x00:
|
||||
/* Supported Pages: List of supported VPD responses. */
|
||||
buf[idx++] = 0x00; /* 0x00: Supported Pages, and: */
|
||||
buf[idx++] = 0x83; /* 0x83: Device Identification. */
|
||||
break;
|
||||
|
||||
case 0x83:
|
||||
/* Device Identification. Each entry is optional, but the entries
|
||||
* included here are modeled after libata's VPD responses.
|
||||
* If the response is given, at least one entry must be present. */
|
||||
|
||||
/* Entry 1: Serial */
|
||||
if (idx + 24 > max_len) {
|
||||
/* Not enough room for even the first entry: */
|
||||
/* 4 byte header + 20 byte string */
|
||||
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
|
||||
ASC_DATA_PHASE_ERROR);
|
||||
return;
|
||||
}
|
||||
buf[idx++] = 0x02; /* Ascii */
|
||||
buf[idx++] = 0x00; /* Vendor Specific */
|
||||
buf[idx++] = 0x00;
|
||||
buf[idx++] = 20; /* Remaining length */
|
||||
padstr8(buf + idx, 20, s->drive_serial_str);
|
||||
idx += 20;
|
||||
|
||||
/* Entry 2: Drive Model and Serial */
|
||||
if (idx + 72 > max_len) {
|
||||
/* 4 (header) + 8 (vendor) + 60 (model & serial) */
|
||||
goto out;
|
||||
}
|
||||
buf[idx++] = 0x02; /* Ascii */
|
||||
buf[idx++] = 0x01; /* T10 Vendor */
|
||||
buf[idx++] = 0x00;
|
||||
buf[idx++] = 68;
|
||||
padstr8(buf + idx, 8, "ATA"); /* Generic T10 vendor */
|
||||
idx += 8;
|
||||
padstr8(buf + idx, 40, s->drive_model_str);
|
||||
idx += 40;
|
||||
padstr8(buf + idx, 20, s->drive_serial_str);
|
||||
idx += 20;
|
||||
|
||||
/* Entry 3: WWN */
|
||||
if (s->wwn && (idx + 12 <= max_len)) {
|
||||
/* 4 byte header + 8 byte wwn */
|
||||
buf[idx++] = 0x01; /* Binary */
|
||||
buf[idx++] = 0x03; /* NAA */
|
||||
buf[idx++] = 0x00;
|
||||
buf[idx++] = 0x08;
|
||||
stq_be_p(&buf[idx], s->wwn);
|
||||
idx += 8;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* SPC-3, revision 23 sec. 6.4 */
|
||||
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
|
||||
ASC_INV_FIELD_IN_CMD_PACKET);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
preamble_len = 5;
|
||||
size_idx = 4;
|
||||
|
||||
buf[0] = 0x05; /* CD-ROM */
|
||||
buf[1] = 0x80; /* removable */
|
||||
buf[2] = 0x00; /* ISO */
|
||||
buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
|
||||
/* buf[size_idx] set below. */
|
||||
buf[5] = 0; /* reserved */
|
||||
buf[6] = 0; /* reserved */
|
||||
buf[7] = 0; /* reserved */
|
||||
padstr8(buf + 8, 8, "QEMU");
|
||||
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
||||
padstr8(buf + 32, 4, s->version);
|
||||
idx = 36;
|
||||
}
|
||||
|
||||
out:
|
||||
buf[size_idx] = idx - preamble_len;
|
||||
ide_atapi_cmd_reply(s, idx, max_len);
|
||||
return;
|
||||
}
|
||||
|
||||
static void cmd_get_configuration(IDEState *s, uint8_t *buf)
|
||||
|
||||
@@ -296,6 +296,7 @@ typedef struct IDEDMAOps IDEDMAOps;
|
||||
#define ASC_INCOMPATIBLE_FORMAT 0x30
|
||||
#define ASC_MEDIUM_NOT_PRESENT 0x3a
|
||||
#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
|
||||
#define ASC_DATA_PHASE_ERROR 0x4b
|
||||
#define ASC_MEDIA_REMOVAL_PREVENTED 0x53
|
||||
|
||||
#define CFA_NO_ERROR 0x00
|
||||
|
||||
+11
-4
@@ -133,7 +133,8 @@ typedef enum BlockOpType {
|
||||
BLOCK_OP_TYPE_BACKUP_SOURCE,
|
||||
BLOCK_OP_TYPE_BACKUP_TARGET,
|
||||
BLOCK_OP_TYPE_CHANGE,
|
||||
BLOCK_OP_TYPE_COMMIT,
|
||||
BLOCK_OP_TYPE_COMMIT_SOURCE,
|
||||
BLOCK_OP_TYPE_COMMIT_TARGET,
|
||||
BLOCK_OP_TYPE_DATAPLANE,
|
||||
BLOCK_OP_TYPE_DRIVE_DEL,
|
||||
BLOCK_OP_TYPE_EJECT,
|
||||
@@ -396,7 +397,11 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
|
||||
void bdrv_get_backing_filename(BlockDriverState *bs,
|
||||
char *filename, int filename_size);
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs,
|
||||
char *dest, size_t sz);
|
||||
char *dest, size_t sz, Error **errp);
|
||||
void bdrv_get_full_backing_filename_from_filename(const char *backed,
|
||||
const char *backing,
|
||||
char *dest, size_t sz,
|
||||
Error **errp);
|
||||
int bdrv_is_snapshot(BlockDriverState *bs);
|
||||
|
||||
int path_has_protocol(const char *path);
|
||||
@@ -434,8 +439,10 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
|
||||
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
|
||||
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
|
||||
int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t cur_sector, int nr_sectors);
|
||||
void bdrv_dirty_iter_init(BlockDriverState *bs,
|
||||
BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
|
||||
int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
|
||||
|
||||
@@ -216,14 +216,4 @@ void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
|
||||
*/
|
||||
void coroutine_fn yield_until_fd_readable(int fd);
|
||||
|
||||
/**
|
||||
* Add or subtract from the coroutine pool size
|
||||
*
|
||||
* The coroutine implementation keeps a pool of coroutines to be reused by
|
||||
* qemu_coroutine_create(). This makes coroutine creation cheap. Heavy
|
||||
* coroutine users should call this to reserve pool space. Call it again with
|
||||
* a negative number to release pool space.
|
||||
*/
|
||||
void qemu_coroutine_adjust_pool_size(int n);
|
||||
|
||||
#endif /* QEMU_COROUTINE_H */
|
||||
|
||||
+13
-2
@@ -191,8 +191,19 @@ struct { \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD_ATOMIC(head, elm, field) do { \
|
||||
do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
} while (atomic_cmpxchg(&(head)->slh_first, (elm)->field.sle_next, \
|
||||
(elm)) != (elm)->field.sle_next); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_MOVE_ATOMIC(dest, src) do { \
|
||||
(dest)->slh_first = atomic_xchg(&(src)->slh_first, NULL); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_REMOVE_HEAD(head, field) do { \
|
||||
|
||||
@@ -61,4 +61,8 @@ bool qemu_thread_is_self(QemuThread *thread);
|
||||
void qemu_thread_exit(void *retval);
|
||||
void qemu_thread_naming(bool enable);
|
||||
|
||||
struct Notifier;
|
||||
void qemu_thread_atexit_add(struct Notifier *notifier);
|
||||
void qemu_thread_atexit_remove(struct Notifier *notifier);
|
||||
|
||||
#endif
|
||||
|
||||
+5
-4
@@ -303,7 +303,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
||||
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
|
||||
nr_sectors, blk_mig_read_cb, blk);
|
||||
|
||||
bdrv_reset_dirty(bs, cur_sector, nr_sectors);
|
||||
bdrv_reset_dirty_bitmap(bs, bmds->dirty_bitmap, cur_sector, nr_sectors);
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
bmds->cur_sector = cur_sector + nr_sectors;
|
||||
@@ -496,7 +496,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
||||
g_free(blk);
|
||||
}
|
||||
|
||||
bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
|
||||
bdrv_reset_dirty_bitmap(bmds->bs, bmds->dirty_bitmap, sector,
|
||||
nr_sectors);
|
||||
break;
|
||||
}
|
||||
sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||
@@ -765,8 +766,8 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
||||
block_mig_state.read_done * BLOCK_SIZE;
|
||||
|
||||
/* Report at least one block pending during bulk phase */
|
||||
if (pending == 0 && !block_mig_state.bulk_completed) {
|
||||
pending = BLOCK_SIZE;
|
||||
if (pending <= max_size && !block_mig_state.bulk_completed) {
|
||||
pending = max_size + BLOCK_SIZE;
|
||||
}
|
||||
blk_mig_unlock();
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user