Compare commits
135
Commits
v2.9.0-rc2
...
v2.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
359c41abe3 | ||
|
|
ca55019dac | ||
|
|
d1263f8f18 | ||
|
|
91af091f92 | ||
|
|
178bd438af | ||
|
|
9c6b899f7a | ||
|
|
372b3fe0b2 | ||
|
|
e3e0003a8f | ||
|
|
5eceb01adf | ||
|
|
f5ac5cfeb6 | ||
|
|
2ec9a782d1 | ||
|
|
1606e4cf8a | ||
|
|
7a9e51198c | ||
|
|
aa388ddc36 | ||
|
|
76296dff97 | ||
|
|
49ca625913 | ||
|
|
e92f0e1910 | ||
|
|
324ec3e4f2 | ||
|
|
aef4278c5a | ||
|
|
052a75721f | ||
|
|
8865852e00 | ||
|
|
ba9e75ceef | ||
|
|
d90fce9446 | ||
|
|
aabf591007 | ||
|
|
14e9559f46 | ||
|
|
17fa24b79c | ||
|
|
86dbcdd9c7 | ||
|
|
c322fdd41a | ||
|
|
0a49bfa1ab | ||
|
|
ad04d8cb2f | ||
|
|
982263ce71 | ||
|
|
1d05906b95 | ||
|
|
eda5f7c6a1 | ||
|
|
512d3c8071 | ||
|
|
e4cd96571f | ||
|
|
0524838225 | ||
|
|
243c5f77f6 | ||
|
|
bf51c7206f | ||
|
|
b4e79a502f | ||
|
|
8695350357 | ||
|
|
4ffcdef427 | ||
|
|
8037fa55ac | ||
|
|
5daf9b3025 | ||
|
|
19dd29e8a7 | ||
|
|
bb2614e991 | ||
|
|
c26a5ab713 | ||
|
|
1bf03e66fd | ||
|
|
89aa0465b9 | ||
|
|
5694923ad1 | ||
|
|
7a25fcd056 | ||
|
|
0d0676a104 | ||
|
|
02be4aeb93 | ||
|
|
d35ff5e6b3 | ||
|
|
a703d3aef5 | ||
|
|
5fe2339e6b | ||
|
|
8f419c5b43 | ||
|
|
54d689988c | ||
|
|
8c9f42f3cf | ||
|
|
1fde6ee885 | ||
|
|
1413c663c9 | ||
|
|
2c9938c5d7 | ||
|
|
6d54af0ea9 | ||
|
|
18adde86dd | ||
|
|
193982c6f9 | ||
|
|
fa902c8ca0 | ||
|
|
b8a68728b6 | ||
|
|
0e5d6327f3 | ||
|
|
87cc4c6102 | ||
|
|
d9123d09f7 | ||
|
|
ecbddbb106 | ||
|
|
b1a419ec79 | ||
|
|
86d1bd7098 | ||
|
|
f82c5b17ea | ||
|
|
0c1bd4692f | ||
|
|
07ff948bd1 | ||
|
|
6aabeb5839 | ||
|
|
d1c136885b | ||
|
|
9445673ea6 | ||
|
|
216411b839 | ||
|
|
8bc0673f6d | ||
|
|
fce5d5386d | ||
|
|
129c7d1c53 | ||
|
|
a6c76285f2 | ||
|
|
d2e49aad72 | ||
|
|
ca0b64e5ed | ||
|
|
9588c5897b | ||
|
|
102a3d8478 | ||
|
|
230f4c6bc5 | ||
|
|
6499fd151d | ||
|
|
5c32be5baf | ||
|
|
709a340d67 | ||
|
|
90c4fe5fc5 | ||
|
|
f9e46d37bd | ||
|
|
9eb5adae26 | ||
|
|
fa03cb7fd2 | ||
|
|
1684907c92 | ||
|
|
243afe858b | ||
|
|
6954cdc070 | ||
|
|
8149e2992f | ||
|
|
cc1e139139 | ||
|
|
cb9a05a4f1 | ||
|
|
c7f15bc936 | ||
|
|
b9afaba891 | ||
|
|
34634ca286 | ||
|
|
6b9d62db89 | ||
|
|
e98c6961c8 | ||
|
|
95b31d709b | ||
|
|
93587e3af3 | ||
|
|
37c4a85cd2 | ||
|
|
e7d54416cf | ||
|
|
fd5d23babf | ||
|
|
05a6f451eb | ||
|
|
a0ee3797bf | ||
|
|
4eaf720294 | ||
|
|
b4053c6483 | ||
|
|
1074b879d1 | ||
|
|
8251a72f8b | ||
|
|
ddc2c3a57e | ||
|
|
0d876080a3 | ||
|
|
375f74f473 | ||
|
|
e839001d5b | ||
|
|
a67ec6ee2d | ||
|
|
e68dd68496 | ||
|
|
fb59dabd4f | ||
|
|
b529aec1ee | ||
|
|
fe6824d126 | ||
|
|
24ec2863b1 | ||
|
|
b8adbc6578 | ||
|
|
c53598ed18 | ||
|
|
aa26292859 | ||
|
|
a2f80fdfc6 | ||
|
|
e42f869b51 | ||
|
|
51149a2ac1 | ||
|
|
d4a606b38b | ||
|
|
a7b0ffacc1 |
No files matched your search
@@ -1157,6 +1157,13 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
|
||||
if (file != NULL) {
|
||||
filename = blk_bs(file)->filename;
|
||||
} else {
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting
|
||||
* non-string types would require more care. When @options
|
||||
* come from -blockdev or blockdev_add, its members are typed
|
||||
* according to the QAPI schema, but when they come from
|
||||
* -drive, they're all QString.
|
||||
*/
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
}
|
||||
|
||||
@@ -1324,6 +1331,13 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
BlockDriver *drv = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting non-string
|
||||
* types would require more care. When @options come from
|
||||
* -blockdev or blockdev_add, its members are typed according to
|
||||
* the QAPI schema, but when they come from -drive, they're all
|
||||
* QString.
|
||||
*/
|
||||
drvname = qdict_get_try_str(*options, "driver");
|
||||
if (drvname) {
|
||||
drv = bdrv_find_format(drvname);
|
||||
@@ -1358,6 +1372,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
}
|
||||
|
||||
/* Find the right block driver */
|
||||
/* See cautionary note on accessing @options above */
|
||||
filename = qdict_get_try_str(*options, "filename");
|
||||
|
||||
if (!drvname && protocol) {
|
||||
@@ -1737,6 +1752,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
{
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
|
||||
if (old_bs && new_bs) {
|
||||
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
|
||||
}
|
||||
if (old_bs) {
|
||||
if (old_bs->quiesce_counter && child->role->drained_end) {
|
||||
child->role->drained_end(child);
|
||||
@@ -1837,6 +1855,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
|
||||
|
||||
assert(parent_bs->drv);
|
||||
assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs));
|
||||
parent_bs->drv->bdrv_child_perm(parent_bs, NULL, child_role,
|
||||
perm, shared_perm, &perm, &shared_perm);
|
||||
|
||||
@@ -1987,6 +2006,13 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
|
||||
qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
|
||||
g_free(bdref_key_dot);
|
||||
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting non-string
|
||||
* types would require more care. When @parent_options come from
|
||||
* -blockdev or blockdev_add, its members are typed according to
|
||||
* the QAPI schema, but when they come from -drive, they're all
|
||||
* QString.
|
||||
*/
|
||||
reference = qdict_get_try_str(parent_options, bdref_key);
|
||||
if (reference || qdict_haskey(options, "file.filename")) {
|
||||
backing_filename[0] = '\0';
|
||||
@@ -2059,6 +2085,13 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
|
||||
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
|
||||
g_free(bdref_key_dot);
|
||||
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting non-string
|
||||
* types would require more care. When @options come from
|
||||
* -blockdev or blockdev_add, its members are typed according to
|
||||
* the QAPI schema, but when they come from -drive, they're all
|
||||
* QString.
|
||||
*/
|
||||
reference = qdict_get_try_str(options, bdref_key);
|
||||
if (!filename && !reference && !qdict_size(image_options)) {
|
||||
if (!allow_none) {
|
||||
@@ -2274,9 +2307,13 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
|
||||
* FIXME: we're parsing the QDict to avoid having to create a
|
||||
* QemuOpts just for this, but neither option is optimal. */
|
||||
/*
|
||||
* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
|
||||
* Caution: getting a boolean member of @options requires care.
|
||||
* When @options come from -blockdev or blockdev_add, members are
|
||||
* typed according to the QAPI schema, but when they come from
|
||||
* -drive, they're all QString.
|
||||
*/
|
||||
if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") &&
|
||||
!qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) {
|
||||
flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR);
|
||||
@@ -2298,6 +2335,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
/* Find the right image format driver */
|
||||
/* See cautionary note on accessing @options above */
|
||||
drvname = qdict_get_try_str(options, "driver");
|
||||
if (drvname) {
|
||||
drv = bdrv_find_format(drvname);
|
||||
@@ -2309,6 +2347,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
||||
|
||||
assert(drvname || !(flags & BDRV_O_PROTOCOL));
|
||||
|
||||
/* See cautionary note on accessing @options above */
|
||||
backing = qdict_get_try_str(options, "backing");
|
||||
if (backing && *backing == '\0') {
|
||||
flags |= BDRV_O_NO_BACKING;
|
||||
@@ -2787,6 +2826,13 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
do {
|
||||
QString *new_obj = qobject_to_qstring(entry->value);
|
||||
const char *new = qstring_get_str(new_obj);
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting
|
||||
* non-string types would require more care. When
|
||||
* bs->options come from -blockdev or blockdev_add, its
|
||||
* members are typed according to the QAPI schema, but
|
||||
* when they come from -drive, they're all QString.
|
||||
*/
|
||||
const char *old = qdict_get_try_str(reopen_state->bs->options,
|
||||
entry->key);
|
||||
|
||||
@@ -3228,7 +3274,11 @@ int bdrv_truncate(BdrvChild *child, int64_t offset)
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
assert(child->perm & BLK_PERM_RESIZE);
|
||||
/* FIXME: Some format block drivers use this function instead of implicitly
|
||||
* growing their file by writing beyond its end.
|
||||
* See bdrv_aligned_pwritev() for an explanation why we currently
|
||||
* cannot assert this permission in that case. */
|
||||
// assert(child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
if (!drv)
|
||||
return -ENOMEDIUM;
|
||||
@@ -4278,6 +4328,11 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
|
||||
return bs->aio_context;
|
||||
}
|
||||
|
||||
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
|
||||
{
|
||||
aio_co_enter(bdrv_get_aio_context(bs), co);
|
||||
}
|
||||
|
||||
static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
|
||||
{
|
||||
QLIST_REMOVE(ban, list);
|
||||
@@ -4350,11 +4405,12 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
{
|
||||
AioContext *ctx;
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_disable_external(ctx);
|
||||
bdrv_parent_drained_begin(bs);
|
||||
bdrv_drain(bs); /* ensure there are no in-flight requests */
|
||||
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
while (aio_poll(ctx, false)) {
|
||||
/* wait for all bottom halves to execute */
|
||||
}
|
||||
@@ -4366,6 +4422,8 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
|
||||
*/
|
||||
aio_context_acquire(new_context);
|
||||
bdrv_attach_aio_context(bs, new_context);
|
||||
bdrv_parent_drained_end(bs);
|
||||
aio_enable_external(ctx);
|
||||
aio_context_release(new_context);
|
||||
}
|
||||
|
||||
|
||||
+44
-3
@@ -61,6 +61,7 @@ struct BlockBackend {
|
||||
|
||||
uint64_t perm;
|
||||
uint64_t shared_perm;
|
||||
bool disable_perm;
|
||||
|
||||
bool allow_write_beyond_eof;
|
||||
|
||||
@@ -230,6 +231,9 @@ static void blk_delete(BlockBackend *blk)
|
||||
assert(!blk->refcnt);
|
||||
assert(!blk->name);
|
||||
assert(!blk->dev);
|
||||
if (blk->public.throttle_state) {
|
||||
blk_io_limits_disable(blk);
|
||||
}
|
||||
if (blk->root) {
|
||||
blk_remove_bs(blk);
|
||||
}
|
||||
@@ -578,7 +582,7 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (blk->root) {
|
||||
if (blk->root && !blk->disable_perm) {
|
||||
ret = bdrv_child_try_set_perm(blk->root, perm, shared_perm, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@@ -597,15 +601,52 @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
|
||||
*shared_perm = blk->shared_perm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifies the user of all BlockBackends that migration has completed. qdev
|
||||
* devices can tighten their permissions in response (specifically revoke
|
||||
* shared write permissions that we needed for storage migration).
|
||||
*
|
||||
* If an error is returned, the VM cannot be allowed to be resumed.
|
||||
*/
|
||||
void blk_resume_after_migration(Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
Error *local_err = NULL;
|
||||
|
||||
for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
|
||||
if (!blk->disable_perm) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blk->disable_perm = false;
|
||||
|
||||
blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
blk->disable_perm = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
|
||||
{
|
||||
if (blk->dev) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* While migration is still incoming, we don't need to apply the
|
||||
* permissions of guest device BlockBackends. We might still have a block
|
||||
* job or NBD server writing to the image for storage migration. */
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
blk->disable_perm = true;
|
||||
}
|
||||
|
||||
blk_ref(blk);
|
||||
blk->dev = dev;
|
||||
blk->legacy_dev = false;
|
||||
blk_iostatus_reset(blk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1007,7 +1048,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
co_entry(&rwco);
|
||||
} else {
|
||||
Coroutine *co = qemu_coroutine_create(co_entry, &rwco);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(blk_bs(blk), co);
|
||||
BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
|
||||
}
|
||||
|
||||
@@ -1114,7 +1155,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||
acb->has_returned = false;
|
||||
|
||||
co = qemu_coroutine_create(co_entry, acb);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(blk_bs(blk), co);
|
||||
|
||||
acb->has_returned = true;
|
||||
if (acb->rwco.ret != NOT_DONE) {
|
||||
|
||||
@@ -335,6 +335,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
if (commit_top_bs == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
commit_top_bs->total_sectors = top->total_sectors;
|
||||
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
|
||||
|
||||
bdrv_set_backing_hd(commit_top_bs, top, &local_err);
|
||||
if (local_err) {
|
||||
@@ -482,6 +484,7 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
error_report_err(local_err);
|
||||
goto ro_cleanup;
|
||||
}
|
||||
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(backing_file_bs));
|
||||
|
||||
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
|
||||
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
|
||||
|
||||
@@ -659,6 +659,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
const char *cookie;
|
||||
double d;
|
||||
const char *secretid;
|
||||
const char *protocol_delimiter;
|
||||
|
||||
static int inited = 0;
|
||||
|
||||
@@ -700,6 +701,15 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) ||
|
||||
!strstart(protocol_delimiter, "://", NULL))
|
||||
{
|
||||
error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not "
|
||||
"start with '%s://')", bs->drv->protocol_name, file,
|
||||
bs->drv->protocol_name);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
|
||||
secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);
|
||||
|
||||
|
||||
@@ -2193,6 +2193,12 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/*
|
||||
* Caution: while qdict_get_str() is fine, getting non-string types
|
||||
* would require more care. When @options come from -blockdev or
|
||||
* blockdev_add, its members are typed according to the QAPI
|
||||
* schema, but when they come from -drive, they're all QString.
|
||||
*/
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
char bsd_path[MAXPATHLEN] = "";
|
||||
bool error_occurred = false;
|
||||
|
||||
+18
-10
@@ -412,10 +412,12 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
glfs_set_preopened(gconf->volume, glfs);
|
||||
|
||||
for (server = gconf->server; server; server = server->next) {
|
||||
if (server->value->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
switch (server->value->type) {
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_UNIX:
|
||||
ret = glfs_set_volfile_server(glfs, "unix",
|
||||
server->value->u.q_unix.path, 0);
|
||||
} else {
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_INET:
|
||||
if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
|
||||
port > 65535) {
|
||||
error_setg(errp, "'%s' is not a valid port number",
|
||||
@@ -426,6 +428,11 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
||||
ret = glfs_set_volfile_server(glfs, "tcp",
|
||||
server->value->u.inet.host,
|
||||
(int)port);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_VSOCK:
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_FD:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -487,7 +494,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
char *str = NULL;
|
||||
const char *ptr;
|
||||
size_t num_servers;
|
||||
int i;
|
||||
int i, type;
|
||||
|
||||
/* create opts info from runtime_json_opts list */
|
||||
opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
|
||||
@@ -539,16 +546,17 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
|
||||
if (!strcmp(ptr, "tcp")) {
|
||||
ptr = "inet"; /* accept legacy "tcp" */
|
||||
}
|
||||
gsconf->type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
|
||||
SOCKET_ADDRESS_FLAT_TYPE__MAX, -1,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_append_hint(&local_err,
|
||||
"Parameter '%s' may be 'inet' or 'unix'\n",
|
||||
GLUSTER_OPT_TYPE);
|
||||
type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
|
||||
SOCKET_ADDRESS_FLAT_TYPE__MAX, -1, NULL);
|
||||
if (type != SOCKET_ADDRESS_FLAT_TYPE_INET
|
||||
&& type != SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
error_setg(&local_err,
|
||||
"Parameter '%s' may be 'inet' or 'unix'",
|
||||
GLUSTER_OPT_TYPE);
|
||||
error_append_hint(&local_err, GERR_INDEX_HINT, i);
|
||||
goto out;
|
||||
}
|
||||
gsconf->type = type;
|
||||
qemu_opts_del(opts);
|
||||
|
||||
if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
|
||||
+56
-22
@@ -44,7 +44,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque);
|
||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int count, BdrvRequestFlags flags);
|
||||
|
||||
static void bdrv_parent_drained_begin(BlockDriverState *bs)
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *c;
|
||||
|
||||
@@ -55,7 +55,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_parent_drained_end(BlockDriverState *bs)
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *c;
|
||||
|
||||
@@ -158,7 +158,7 @@ bool bdrv_requests_pending(BlockDriverState *bs)
|
||||
|
||||
static bool bdrv_drain_recurse(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child;
|
||||
BdrvChild *child, *tmp;
|
||||
bool waited;
|
||||
|
||||
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
|
||||
@@ -167,8 +167,25 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
|
||||
bs->drv->bdrv_drain(bs);
|
||||
}
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
waited |= bdrv_drain_recurse(child->bs);
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
|
||||
BlockDriverState *bs = child->bs;
|
||||
bool in_main_loop =
|
||||
qemu_get_current_aio_context() == qemu_get_aio_context();
|
||||
assert(bs->refcnt > 0);
|
||||
if (in_main_loop) {
|
||||
/* In case the recursive bdrv_drain_recurse processes a
|
||||
* block_job_defer_to_main_loop BH and modifies the graph,
|
||||
* let's hold a reference to bs until we are done.
|
||||
*
|
||||
* IOThread doesn't have such a BH, and it is not safe to call
|
||||
* bdrv_unref without BQL, so skip doing it there.
|
||||
*/
|
||||
bdrv_ref(bs);
|
||||
}
|
||||
waited |= bdrv_drain_recurse(bs);
|
||||
if (in_main_loop) {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
}
|
||||
|
||||
return waited;
|
||||
@@ -616,7 +633,7 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
|
||||
bdrv_rw_co_entry(&rwco);
|
||||
} else {
|
||||
co = qemu_coroutine_create(bdrv_rw_co_entry, &rwco);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(child->bs, co);
|
||||
BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
|
||||
}
|
||||
return rwco.ret;
|
||||
@@ -945,7 +962,14 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
|
||||
size_t skip_bytes;
|
||||
int ret;
|
||||
|
||||
assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
/* FIXME We cannot require callers to have write permissions when all they
|
||||
* are doing is a read request. If we did things right, write permissions
|
||||
* would be obtained anyway, but internally by the copy-on-read code. As
|
||||
* long as it is implemented here rather than in a separat filter driver,
|
||||
* the copy-on-read code doesn't have its own BdrvChild, however, for which
|
||||
* it could request permissions. Therefore we have to bypass the permission
|
||||
* system for the moment. */
|
||||
// assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
|
||||
/* Cover entire cluster so no additional backing file I/O is required when
|
||||
* allocating cluster in the image file.
|
||||
@@ -1338,8 +1362,16 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
assert(!waited || !req->serialising);
|
||||
assert(req->overlap_offset <= offset);
|
||||
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
|
||||
assert(child->perm & BLK_PERM_WRITE);
|
||||
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
/* FIXME: Block migration uses the BlockBackend of the guest device at a
|
||||
* point when it has not yet taken write permissions. This will be
|
||||
* fixed by a future patch, but for now we have to bypass this
|
||||
* assertion for block migration to work. */
|
||||
// assert(child->perm & BLK_PERM_WRITE);
|
||||
/* FIXME: Because of the above, we also cannot guarantee that all format
|
||||
* BDS take the BLK_PERM_RESIZE permission on their file BDS, since
|
||||
* they are not obligated to do so if they do not have any parent
|
||||
* that has taken the permission to write to them. */
|
||||
// assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
@@ -1873,7 +1905,7 @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs,
|
||||
} else {
|
||||
co = qemu_coroutine_create(bdrv_get_block_status_above_co_entry,
|
||||
&data);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
BDRV_POLL_WHILE(bs, !data.done);
|
||||
}
|
||||
return data.ret;
|
||||
@@ -1999,7 +2031,7 @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos,
|
||||
};
|
||||
Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data);
|
||||
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
aio_poll(bdrv_get_aio_context(bs), true);
|
||||
}
|
||||
@@ -2216,7 +2248,7 @@ static BlockAIOCB *bdrv_co_aio_prw_vector(BdrvChild *child,
|
||||
acb->is_write = is_write;
|
||||
|
||||
co = qemu_coroutine_create(bdrv_co_do_rw, acb);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(child->bs, co);
|
||||
|
||||
bdrv_co_maybe_schedule_bh(acb);
|
||||
return &acb->common;
|
||||
@@ -2247,7 +2279,7 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
||||
acb->req.error = -EINPROGRESS;
|
||||
|
||||
co = qemu_coroutine_create(bdrv_aio_flush_co_entry, acb);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
|
||||
bdrv_co_maybe_schedule_bh(acb);
|
||||
return &acb->common;
|
||||
@@ -2271,16 +2303,17 @@ static void coroutine_fn bdrv_flush_co_entry(void *opaque)
|
||||
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
|
||||
bdrv_is_sg(bs)) {
|
||||
return 0;
|
||||
}
|
||||
int current_gen;
|
||||
int ret = 0;
|
||||
|
||||
bdrv_inc_in_flight(bs);
|
||||
|
||||
int current_gen = bs->write_gen;
|
||||
if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
|
||||
bdrv_is_sg(bs)) {
|
||||
goto early_exit;
|
||||
}
|
||||
|
||||
current_gen = bs->write_gen;
|
||||
|
||||
/* Wait until any previous flushes are completed */
|
||||
while (bs->active_flush_req) {
|
||||
@@ -2363,6 +2396,7 @@ out:
|
||||
/* Return value is ignored - it's ok if wait queue is empty */
|
||||
qemu_co_queue_next(&bs->flush_queue);
|
||||
|
||||
early_exit:
|
||||
bdrv_dec_in_flight(bs);
|
||||
return ret;
|
||||
}
|
||||
@@ -2380,7 +2414,7 @@ int bdrv_flush(BlockDriverState *bs)
|
||||
bdrv_flush_co_entry(&flush_co);
|
||||
} else {
|
||||
co = qemu_coroutine_create(bdrv_flush_co_entry, &flush_co);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
BDRV_POLL_WHILE(bs, flush_co.ret == NOT_DONE);
|
||||
}
|
||||
|
||||
@@ -2527,7 +2561,7 @@ int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
bdrv_pdiscard_co_entry(&rwco);
|
||||
} else {
|
||||
co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
BDRV_POLL_WHILE(bs, rwco.ret == NOT_DONE);
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -103,7 +103,6 @@ typedef struct IscsiTask {
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUIOVector *qiov;
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
struct scsi_task *task;
|
||||
@@ -2093,6 +2092,7 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
BlockDriverState *bs;
|
||||
IscsiLun *iscsilun = NULL;
|
||||
QDict *bs_options;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs = bdrv_new();
|
||||
|
||||
@@ -2103,8 +2103,13 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
iscsilun = bs->opaque;
|
||||
|
||||
bs_options = qdict_new();
|
||||
qdict_put(bs_options, "filename", qstring_from_str(filename));
|
||||
ret = iscsi_open(bs, bs_options, 0, NULL);
|
||||
iscsi_parse_filename(filename, bs_options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = iscsi_open(bs, bs_options, 0, NULL);
|
||||
}
|
||||
QDECREF(bs_options);
|
||||
|
||||
if (ret != 0) {
|
||||
|
||||
+11
-2
@@ -1148,9 +1148,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
return;
|
||||
}
|
||||
mirror_top_bs->total_sectors = bs->total_sectors;
|
||||
bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));
|
||||
|
||||
/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
|
||||
* it alive until block_job_create() even if bs has no parent. */
|
||||
* it alive until block_job_create() succeeds even if bs has no parent. */
|
||||
bdrv_ref(mirror_top_bs);
|
||||
bdrv_drained_begin(bs);
|
||||
bdrv_append(mirror_top_bs, bs, &local_err);
|
||||
@@ -1168,10 +1169,12 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
|
||||
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
|
||||
creation_flags, cb, opaque, errp);
|
||||
bdrv_unref(mirror_top_bs);
|
||||
if (!s) {
|
||||
goto fail;
|
||||
}
|
||||
/* The block job now has a reference to this node */
|
||||
bdrv_unref(mirror_top_bs);
|
||||
|
||||
s->source = bs;
|
||||
s->mirror_top_bs = mirror_top_bs;
|
||||
|
||||
@@ -1242,6 +1245,10 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
|
||||
fail:
|
||||
if (s) {
|
||||
/* Make sure this BDS does not go away until we have completed the graph
|
||||
* changes below */
|
||||
bdrv_ref(mirror_top_bs);
|
||||
|
||||
g_free(s->replaces);
|
||||
blk_unref(s->target);
|
||||
block_job_unref(&s->common);
|
||||
@@ -1250,6 +1257,8 @@ fail:
|
||||
bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
|
||||
&error_abort);
|
||||
bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
|
||||
|
||||
bdrv_unref(mirror_top_bs);
|
||||
}
|
||||
|
||||
void mirror_start(const char *job_id, BlockDriverState *bs,
|
||||
|
||||
+38
-25
@@ -47,7 +47,7 @@ typedef struct BDRVNBDState {
|
||||
NBDClientSession client;
|
||||
|
||||
/* For nbd_refresh_filename() */
|
||||
SocketAddress *saddr;
|
||||
SocketAddressFlat *saddr;
|
||||
char *export, *tlscredsid;
|
||||
} BDRVNBDState;
|
||||
|
||||
@@ -95,7 +95,7 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
goto out;
|
||||
}
|
||||
qdict_put(options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(options, "server.data.path",
|
||||
qdict_put(options, "server.path",
|
||||
qstring_from_str(qp->p[0].value));
|
||||
} else {
|
||||
QString *host;
|
||||
@@ -116,10 +116,10 @@ static int nbd_parse_uri(const char *filename, QDict *options)
|
||||
}
|
||||
|
||||
qdict_put(options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(options, "server.data.host", host);
|
||||
qdict_put(options, "server.host", host);
|
||||
|
||||
port_str = g_strdup_printf("%d", uri->port ?: NBD_DEFAULT_PORT);
|
||||
qdict_put(options, "server.data.port", qstring_from_str(port_str));
|
||||
qdict_put(options, "server.port", qstring_from_str(port_str));
|
||||
g_free(port_str);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
||||
/* are we a UNIX or TCP socket? */
|
||||
if (strstart(host_spec, "unix:", &unixpath)) {
|
||||
qdict_put(options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(options, "server.data.path", qstring_from_str(unixpath));
|
||||
qdict_put(options, "server.path", qstring_from_str(unixpath));
|
||||
} else {
|
||||
InetSocketAddress *addr = NULL;
|
||||
|
||||
@@ -207,8 +207,8 @@ static void nbd_parse_filename(const char *filename, QDict *options,
|
||||
}
|
||||
|
||||
qdict_put(options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(options, "server.data.host", qstring_from_str(addr->host));
|
||||
qdict_put(options, "server.data.port", qstring_from_str(addr->port));
|
||||
qdict_put(options, "server.host", qstring_from_str(addr->host));
|
||||
qdict_put(options, "server.port", qstring_from_str(addr->port));
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
}
|
||||
|
||||
@@ -248,20 +248,21 @@ static bool nbd_process_legacy_socket_options(QDict *output_options,
|
||||
}
|
||||
|
||||
qdict_put(output_options, "server.type", qstring_from_str("unix"));
|
||||
qdict_put(output_options, "server.data.path", qstring_from_str(path));
|
||||
qdict_put(output_options, "server.path", qstring_from_str(path));
|
||||
} else if (host) {
|
||||
qdict_put(output_options, "server.type", qstring_from_str("inet"));
|
||||
qdict_put(output_options, "server.data.host", qstring_from_str(host));
|
||||
qdict_put(output_options, "server.data.port",
|
||||
qdict_put(output_options, "server.host", qstring_from_str(host));
|
||||
qdict_put(output_options, "server.port",
|
||||
qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp)
|
||||
static SocketAddressFlat *nbd_config(BDRVNBDState *s, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
SocketAddress *saddr = NULL;
|
||||
SocketAddressFlat *saddr = NULL;
|
||||
QDict *addr = NULL;
|
||||
QObject *crumpled_addr = NULL;
|
||||
Visitor *iv = NULL;
|
||||
@@ -278,8 +279,16 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
|
||||
* server.type=inet. .to doesn't matter, it's ignored anyway.
|
||||
* That's because when @options come from -blockdev or
|
||||
* blockdev_add, members are typed according to the QAPI schema,
|
||||
* but when they come from -drive, they're all QString. The
|
||||
* visitor expects the former.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_addr);
|
||||
visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
|
||||
visit_type_SocketAddressFlat(iv, NULL, &saddr, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto done;
|
||||
@@ -298,9 +307,10 @@ NBDClientSession *nbd_get_client_session(BlockDriverState *bs)
|
||||
return &s->client;
|
||||
}
|
||||
|
||||
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
|
||||
static QIOChannelSocket *nbd_establish_connection(SocketAddressFlat *saddr_flat,
|
||||
Error **errp)
|
||||
{
|
||||
SocketAddress *saddr = socket_address_crumple(saddr_flat);
|
||||
QIOChannelSocket *sioc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -310,7 +320,9 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
|
||||
qio_channel_socket_connect_sync(sioc,
|
||||
saddr,
|
||||
&local_err);
|
||||
qapi_free_SocketAddress(saddr);
|
||||
if (local_err) {
|
||||
object_unref(OBJECT(sioc));
|
||||
error_propagate(errp, local_err);
|
||||
return NULL;
|
||||
}
|
||||
@@ -401,7 +413,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Translate @host, @port, and @path to a SocketAddress */
|
||||
/* Translate @host, @port, and @path to a SocketAddressFlat */
|
||||
if (!nbd_process_legacy_socket_options(options, opts, errp)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -421,11 +433,12 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (s->saddr->type != SOCKET_ADDRESS_KIND_INET) {
|
||||
/* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
|
||||
if (s->saddr->type != SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
error_setg(errp, "TLS only supported over IP sockets");
|
||||
goto error;
|
||||
}
|
||||
hostname = s->saddr->u.inet.data->host;
|
||||
hostname = s->saddr->u.inet.host;
|
||||
}
|
||||
|
||||
/* establish TCP connection, return error if it fails
|
||||
@@ -448,7 +461,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
object_unref(OBJECT(tlscreds));
|
||||
}
|
||||
if (ret < 0) {
|
||||
qapi_free_SocketAddress(s->saddr);
|
||||
qapi_free_SocketAddressFlat(s->saddr);
|
||||
g_free(s->export);
|
||||
g_free(s->tlscredsid);
|
||||
}
|
||||
@@ -474,7 +487,7 @@ static void nbd_close(BlockDriverState *bs)
|
||||
|
||||
nbd_client_close(bs);
|
||||
|
||||
qapi_free_SocketAddress(s->saddr);
|
||||
qapi_free_SocketAddressFlat(s->saddr);
|
||||
g_free(s->export);
|
||||
g_free(s->tlscredsid);
|
||||
}
|
||||
@@ -505,15 +518,15 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
Visitor *ov;
|
||||
const char *host = NULL, *port = NULL, *path = NULL;
|
||||
|
||||
if (s->saddr->type == SOCKET_ADDRESS_KIND_INET) {
|
||||
const InetSocketAddress *inet = s->saddr->u.inet.data;
|
||||
if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
|
||||
const InetSocketAddress *inet = &s->saddr->u.inet;
|
||||
if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) {
|
||||
host = inet->host;
|
||||
port = inet->port;
|
||||
}
|
||||
} else if (s->saddr->type == SOCKET_ADDRESS_KIND_UNIX) {
|
||||
path = s->saddr->u.q_unix.data->path;
|
||||
}
|
||||
} else if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
|
||||
path = s->saddr->u.q_unix.path;
|
||||
} /* else can't represent as pseudo-filename */
|
||||
|
||||
qdict_put(opts, "driver", qstring_from_str("nbd"));
|
||||
|
||||
@@ -532,7 +545,7 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
}
|
||||
|
||||
ov = qobject_output_visitor_new(&saddr_qdict);
|
||||
visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
|
||||
visit_type_SocketAddressFlat(ov, NULL, &s->saddr, &error_abort);
|
||||
visit_complete(ov, &saddr_qdict);
|
||||
visit_free(ov);
|
||||
qdict_put_obj(opts, "server", saddr_qdict);
|
||||
|
||||
@@ -474,6 +474,13 @@ static NFSServer *nfs_config(QDict *options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caution: this works only because all scalar members of
|
||||
* NFSServer are QString in @crumpled_addr. The visitor expects
|
||||
* @crumpled_addr to be typed according to the QAPI schema. It
|
||||
* is when @options come from -blockdev or blockdev_add. But when
|
||||
* they come from -drive, they're all QString.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_addr);
|
||||
visit_type_NFSServer(iv, NULL, &server, &local_error);
|
||||
if (local_error) {
|
||||
|
||||
+13
-6
@@ -192,8 +192,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
BDRVParallelsState *s = bs->opaque;
|
||||
uint32_t idx, to_allocate, i;
|
||||
int64_t pos, space;
|
||||
int64_t pos, space, idx, to_allocate, i;
|
||||
|
||||
pos = block_status(s, sector_num, nb_sectors, pnum);
|
||||
if (pos > 0) {
|
||||
@@ -201,11 +200,19 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
idx = sector_num / s->tracks;
|
||||
if (idx >= s->bat_size) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
to_allocate = DIV_ROUND_UP(sector_num + *pnum, s->tracks) - idx;
|
||||
|
||||
/* This function is called only by parallels_co_writev(), which will never
|
||||
* pass a sector_num at or beyond the end of the image (because the block
|
||||
* layer never passes such a sector_num to that function). Therefore, idx
|
||||
* is always below s->bat_size.
|
||||
* block_status() will limit *pnum so that sector_num + *pnum will not
|
||||
* exceed the image end. Therefore, idx + to_allocate cannot exceed
|
||||
* s->bat_size.
|
||||
* Note that s->bat_size is an unsigned int, therefore idx + to_allocate
|
||||
* will always fit into a uint32_t. */
|
||||
assert(idx < s->bat_size && idx + to_allocate <= s->bat_size);
|
||||
|
||||
space = to_allocate * s->tracks;
|
||||
if (s->data_end + space > bdrv_getlength(bs->file->bs) >> BDRV_SECTOR_BITS) {
|
||||
int ret;
|
||||
|
||||
@@ -1519,12 +1519,10 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
|
||||
|
||||
/* Round start up and end down */
|
||||
offset = align_offset(offset, s->cluster_size);
|
||||
end_offset = start_of_cluster(s, end_offset);
|
||||
|
||||
if (offset > end_offset) {
|
||||
return 0;
|
||||
/* The caller must cluster-align start; round end down except at EOF */
|
||||
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
|
||||
if (end_offset != bs->total_sectors * BDRV_SECTOR_SIZE) {
|
||||
end_offset = start_of_cluster(s, end_offset);
|
||||
}
|
||||
|
||||
nb_clusters = size_to_clusters(s, end_offset - offset);
|
||||
|
||||
+48
-41
@@ -20,6 +20,7 @@
|
||||
#include "crypto/secret.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
/*
|
||||
* When specifying the image filename use:
|
||||
@@ -135,18 +136,16 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
const char *start;
|
||||
char *p, *buf, *keypairs;
|
||||
char *p, *buf;
|
||||
QList *keypairs = NULL;
|
||||
char *found_str;
|
||||
size_t max_keypair_size;
|
||||
|
||||
if (!strstart(filename, "rbd:", &start)) {
|
||||
error_setg(errp, "File name must start with 'rbd:'");
|
||||
return;
|
||||
}
|
||||
|
||||
max_keypair_size = strlen(start) + 1;
|
||||
buf = g_strdup(start);
|
||||
keypairs = g_malloc0(max_keypair_size);
|
||||
p = buf;
|
||||
|
||||
found_str = qemu_rbd_next_tok(p, '/', &p);
|
||||
@@ -194,33 +193,30 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
|
||||
} else if (!strcmp(name, "id")) {
|
||||
qdict_put(options, "user" , qstring_from_str(value));
|
||||
} else {
|
||||
/* FIXME: This is pretty ugly, and not the right way to do this.
|
||||
* These should be contained in a structure, and then
|
||||
* passed explicitly as individual key/value pairs to
|
||||
* rados. Consider this legacy code that needs to be
|
||||
* updated. */
|
||||
char *tmp = g_malloc0(max_keypair_size);
|
||||
/* only use a delimiter if it is not the first keypair found */
|
||||
/* These are sets of unknown key/value pairs we'll pass along
|
||||
* to ceph */
|
||||
if (keypairs[0]) {
|
||||
snprintf(tmp, max_keypair_size, ":%s=%s", name, value);
|
||||
pstrcat(keypairs, max_keypair_size, tmp);
|
||||
} else {
|
||||
snprintf(keypairs, max_keypair_size, "%s=%s", name, value);
|
||||
/*
|
||||
* We pass these internally to qemu_rbd_set_keypairs(), so
|
||||
* we can get away with the simpler list of [ "key1",
|
||||
* "value1", "key2", "value2" ] rather than a raw dict
|
||||
* { "key1": "value1", "key2": "value2" } where we can't
|
||||
* guarantee order, or even a more correct but complex
|
||||
* [ { "key1": "value1" }, { "key2": "value2" } ]
|
||||
*/
|
||||
if (!keypairs) {
|
||||
keypairs = qlist_new();
|
||||
}
|
||||
g_free(tmp);
|
||||
qlist_append(keypairs, qstring_from_str(name));
|
||||
qlist_append(keypairs, qstring_from_str(value));
|
||||
}
|
||||
}
|
||||
|
||||
if (keypairs[0]) {
|
||||
qdict_put(options, "=keyvalue-pairs", qstring_from_str(keypairs));
|
||||
if (keypairs) {
|
||||
qdict_put(options, "=keyvalue-pairs",
|
||||
qobject_to_json(QOBJECT(keypairs)));
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
g_free(buf);
|
||||
g_free(keypairs);
|
||||
QDECREF(keypairs);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,36 +240,41 @@ static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs,
|
||||
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
|
||||
Error **errp)
|
||||
{
|
||||
char *p, *buf;
|
||||
char *name;
|
||||
char *value;
|
||||
QList *keypairs;
|
||||
QString *name;
|
||||
QString *value;
|
||||
const char *key;
|
||||
size_t remaining;
|
||||
int ret = 0;
|
||||
|
||||
buf = g_strdup(keypairs);
|
||||
p = buf;
|
||||
if (!keypairs_json) {
|
||||
return ret;
|
||||
}
|
||||
keypairs = qobject_to_qlist(qobject_from_json(keypairs_json,
|
||||
&error_abort));
|
||||
remaining = qlist_size(keypairs) / 2;
|
||||
assert(remaining);
|
||||
|
||||
while (p) {
|
||||
name = qemu_rbd_next_tok(p, '=', &p);
|
||||
if (!p) {
|
||||
error_setg(errp, "conf option %s has no value", name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
while (remaining--) {
|
||||
name = qobject_to_qstring(qlist_pop(keypairs));
|
||||
value = qobject_to_qstring(qlist_pop(keypairs));
|
||||
assert(name && value);
|
||||
key = qstring_get_str(name);
|
||||
|
||||
value = qemu_rbd_next_tok(p, ':', &p);
|
||||
|
||||
ret = rados_conf_set(cluster, name, value);
|
||||
ret = rados_conf_set(cluster, key, qstring_get_str(value));
|
||||
QDECREF(name);
|
||||
QDECREF(value);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "invalid conf option %s", name);
|
||||
error_setg_errno(errp, -ret, "invalid conf option %s", key);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(buf);
|
||||
QDECREF(keypairs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -384,6 +385,12 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caution: while qdict_get_try_str() is fine, getting non-string
|
||||
* types would require more care. When @options come from -blockdev
|
||||
* or blockdev_add, its members are typed according to the QAPI
|
||||
* schema, but when they come from -drive, they're all QString.
|
||||
*/
|
||||
pool = qdict_get_try_str(options, "pool");
|
||||
conf = qdict_get_try_str(options, "conf");
|
||||
clientname = qdict_get_try_str(options, "user");
|
||||
|
||||
+60
-34
@@ -13,9 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/sockets.h"
|
||||
@@ -547,6 +549,47 @@ static SocketAddress *sd_socket_address(const char *path,
|
||||
return addr;
|
||||
}
|
||||
|
||||
static SocketAddress *sd_server_config(QDict *options, Error **errp)
|
||||
{
|
||||
QDict *server = NULL;
|
||||
QObject *crumpled_server = NULL;
|
||||
Visitor *iv = NULL;
|
||||
SocketAddressFlat *saddr_flat = NULL;
|
||||
SocketAddress *saddr = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
qdict_extract_subqdict(options, &server, "server.");
|
||||
|
||||
crumpled_server = qdict_crumple(server, errp);
|
||||
if (!crumpled_server) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive
|
||||
* server.type=inet. .to doesn't matter, it's ignored anyway.
|
||||
* That's because when @options come from -blockdev or
|
||||
* blockdev_add, members are typed according to the QAPI schema,
|
||||
* but when they come from -drive, they're all QString. The
|
||||
* visitor expects the former.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_server);
|
||||
visit_type_SocketAddressFlat(iv, NULL, &saddr_flat, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
saddr = socket_address_crumple(saddr_flat);
|
||||
|
||||
done:
|
||||
qapi_free_SocketAddressFlat(saddr_flat);
|
||||
visit_free(iv);
|
||||
qobject_decref(crumpled_server);
|
||||
QDECREF(server);
|
||||
return saddr;
|
||||
}
|
||||
|
||||
/* Return -EIO in case of error, file descriptor on success */
|
||||
static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
|
||||
{
|
||||
@@ -693,7 +736,7 @@ static int do_req(int sockfd, BlockDriverState *bs, SheepdogReq *hdr,
|
||||
} else {
|
||||
co = qemu_coroutine_create(do_co_req, &srco);
|
||||
if (bs) {
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(bs, co);
|
||||
BDRV_POLL_WHILE(bs, !srco.finished);
|
||||
} else {
|
||||
qemu_coroutine_enter(co);
|
||||
@@ -899,7 +942,7 @@ static void co_read_response(void *opaque)
|
||||
s->co_recv = qemu_coroutine_create(aio_read_response, opaque);
|
||||
}
|
||||
|
||||
aio_co_wake(s->co_recv);
|
||||
aio_co_enter(s->aio_context, s->co_recv);
|
||||
}
|
||||
|
||||
static void co_write_request(void *opaque)
|
||||
@@ -1174,15 +1217,15 @@ static void sd_parse_filename(const char *filename, QDict *options,
|
||||
return;
|
||||
}
|
||||
|
||||
if (cfg.host) {
|
||||
qdict_set_default_str(options, "host", cfg.host);
|
||||
}
|
||||
if (cfg.port) {
|
||||
snprintf(buf, sizeof(buf), "%d", cfg.port);
|
||||
qdict_set_default_str(options, "port", buf);
|
||||
}
|
||||
if (cfg.path) {
|
||||
qdict_set_default_str(options, "path", cfg.path);
|
||||
qdict_set_default_str(options, "server.path", cfg.path);
|
||||
qdict_set_default_str(options, "server.type", "unix");
|
||||
} else {
|
||||
qdict_set_default_str(options, "server.type", "inet");
|
||||
qdict_set_default_str(options, "server.host",
|
||||
cfg.host ?: SD_DEFAULT_ADDR);
|
||||
snprintf(buf, sizeof(buf), "%d", cfg.port ?: SD_DEFAULT_PORT);
|
||||
qdict_set_default_str(options, "server.port", buf);
|
||||
}
|
||||
qdict_set_default_str(options, "vdi", cfg.vdi);
|
||||
qdict_set_default_str(options, "tag", cfg.tag);
|
||||
@@ -1509,18 +1552,6 @@ static QemuOptsList runtime_opts = {
|
||||
.name = "sheepdog",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "host",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "port",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "path",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "vdi",
|
||||
.type = QEMU_OPT_STRING,
|
||||
@@ -1543,7 +1574,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret, fd;
|
||||
uint32_t vid = 0;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
const char *host, *port, *path, *vdi, *snap_id_str, *tag;
|
||||
const char *vdi, *snap_id_str, *tag;
|
||||
uint64_t snap_id;
|
||||
char *buf = NULL;
|
||||
QemuOpts *opts;
|
||||
@@ -1560,20 +1591,17 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto err_no_fd;
|
||||
}
|
||||
|
||||
host = qemu_opt_get(opts, "host");
|
||||
port = qemu_opt_get(opts, "port");
|
||||
path = qemu_opt_get(opts, "path");
|
||||
s->addr = sd_server_config(options, errp);
|
||||
if (!s->addr) {
|
||||
ret = -EINVAL;
|
||||
goto err_no_fd;
|
||||
}
|
||||
|
||||
vdi = qemu_opt_get(opts, "vdi");
|
||||
snap_id_str = qemu_opt_get(opts, "snap-id");
|
||||
snap_id = qemu_opt_get_number(opts, "snap-id", CURRENT_VDI_ID);
|
||||
tag = qemu_opt_get(opts, "tag");
|
||||
|
||||
if ((host || port) && path) {
|
||||
error_setg(errp, "can't use 'path' together with 'host' or 'port'");
|
||||
ret = -EINVAL;
|
||||
goto err_no_fd;
|
||||
}
|
||||
|
||||
if (!vdi) {
|
||||
error_setg(errp, "parameter 'vdi' is missing");
|
||||
ret = -EINVAL;
|
||||
@@ -1604,8 +1632,6 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto err_no_fd;
|
||||
}
|
||||
|
||||
s->addr = sd_socket_address(path, host, port);
|
||||
|
||||
QLIST_INIT(&s->inflight_aio_head);
|
||||
QLIST_INIT(&s->failed_aio_head);
|
||||
QLIST_INIT(&s->inflight_aiocb_head);
|
||||
|
||||
+23
-3
@@ -27,6 +27,7 @@
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
||||
QemuOptsList internal_snapshot_opts = {
|
||||
.name = "snapshot",
|
||||
@@ -189,14 +190,33 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
if (bs->file) {
|
||||
BlockDriverState *file;
|
||||
QDict *options = qdict_clone_shallow(bs->options);
|
||||
QDict *file_options;
|
||||
|
||||
file = bs->file->bs;
|
||||
/* Prevent it from getting deleted when detached from bs */
|
||||
bdrv_ref(file);
|
||||
|
||||
qdict_extract_subqdict(options, &file_options, "file.");
|
||||
QDECREF(file_options);
|
||||
qdict_put(options, "file", qstring_from_str(bdrv_get_node_name(file)));
|
||||
|
||||
drv->bdrv_close(bs);
|
||||
ret = bdrv_snapshot_goto(bs->file->bs, snapshot_id);
|
||||
open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL);
|
||||
bdrv_unref_child(bs, bs->file);
|
||||
bs->file = NULL;
|
||||
|
||||
ret = bdrv_snapshot_goto(file, snapshot_id);
|
||||
open_ret = drv->bdrv_open(bs, options, bs->open_flags, NULL);
|
||||
QDECREF(options);
|
||||
if (open_ret < 0) {
|
||||
bdrv_unref(bs->file->bs);
|
||||
bdrv_unref(file);
|
||||
bs->drv = NULL;
|
||||
return open_ret;
|
||||
}
|
||||
|
||||
assert(bs->file->bs == file);
|
||||
bdrv_unref(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -601,6 +601,14 @@ static InetSocketAddress *ssh_config(QDict *options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive.
|
||||
* .to doesn't matter, it's ignored anyway.
|
||||
* That's because when @options come from -blockdev or
|
||||
* blockdev_add, members are typed according to the QAPI schema,
|
||||
* but when they come from -drive, they're all QString. The
|
||||
* visitor expects the former.
|
||||
*/
|
||||
iv = qobject_input_visitor_new(crumpled_addr);
|
||||
visit_type_InetSocketAddress(iv, NULL, &inet, &local_error);
|
||||
if (local_error) {
|
||||
|
||||
@@ -124,6 +124,7 @@ void qmp_nbd_server_start(SocketAddress *addr,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
|
||||
if (addr->type != SOCKET_ADDRESS_KIND_INET) {
|
||||
error_setg(errp, "TLS is only supported with IPv4/IPv6");
|
||||
goto error;
|
||||
|
||||
+2
-2
@@ -1772,6 +1772,8 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_set_aio_context(state->new_bs, state->aio_context);
|
||||
|
||||
/* This removes our old bs and adds the new bs. This is an operation that
|
||||
* can fail, so we need to do it in .prepare; undoing it for abort is
|
||||
* always possible. */
|
||||
@@ -1789,8 +1791,6 @@ static void external_snapshot_commit(BlkActionState *common)
|
||||
ExternalSnapshotState *state =
|
||||
DO_UPCAST(ExternalSnapshotState, common, common);
|
||||
|
||||
bdrv_set_aio_context(state->new_bs, state->aio_context);
|
||||
|
||||
/* We don't need (or want) to use the transactional
|
||||
* bdrv_reopen_multiple() across all the entries at once, because we
|
||||
* don't want to abort all of them if one of them fails the reopen */
|
||||
|
||||
+2
-2
@@ -290,7 +290,7 @@ void block_job_start(BlockJob *job)
|
||||
job->pause_count--;
|
||||
job->busy = true;
|
||||
job->paused = false;
|
||||
qemu_coroutine_enter(job->co);
|
||||
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
|
||||
}
|
||||
|
||||
void block_job_ref(BlockJob *job)
|
||||
@@ -532,7 +532,7 @@ void block_job_user_resume(BlockJob *job)
|
||||
void block_job_enter(BlockJob *job)
|
||||
{
|
||||
if (job->co && !job->busy) {
|
||||
qemu_coroutine_enter(job->co);
|
||||
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ typedef struct {
|
||||
int max_size;
|
||||
int do_telnetopt;
|
||||
int do_nodelay;
|
||||
int is_unix;
|
||||
int *read_msgfds;
|
||||
size_t read_msgfds_num;
|
||||
int *write_msgfds;
|
||||
@@ -358,6 +357,10 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
|
||||
return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
|
||||
is_listen ? ",server" : "");
|
||||
break;
|
||||
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||
return g_strdup_printf("%svsock:%s:%s", prefix,
|
||||
addr->u.vsock.data->cid,
|
||||
addr->u.vsock.data->port);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -825,7 +828,6 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
|
||||
QIOChannelSocket *sioc = NULL;
|
||||
|
||||
s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
s->is_listen = is_listen;
|
||||
s->is_telnet = is_telnet;
|
||||
s->do_nodelay = do_nodelay;
|
||||
@@ -865,7 +867,8 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
s->addr = QAPI_CLONE(SocketAddress, sock->addr);
|
||||
|
||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
|
||||
if (s->is_unix) {
|
||||
/* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
|
||||
if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
|
||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
|
||||
}
|
||||
|
||||
|
||||
@@ -323,6 +323,7 @@ replication="yes"
|
||||
|
||||
supported_cpu="no"
|
||||
supported_os="no"
|
||||
bogus_os="no"
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -520,11 +521,11 @@ ARCH=
|
||||
# Normalise host CPU name and set ARCH.
|
||||
# Note that this case should only have supported host CPUs, not guests.
|
||||
case "$cpu" in
|
||||
ppc|ppc64|s390|s390x|x32)
|
||||
ppc|ppc64|s390|s390x|sparc64|x32)
|
||||
cpu="$cpu"
|
||||
supported_cpu="yes"
|
||||
;;
|
||||
ia64|sparc64)
|
||||
ia64)
|
||||
cpu="$cpu"
|
||||
;;
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
@@ -549,6 +550,7 @@ case "$cpu" in
|
||||
;;
|
||||
sparc|sun4[cdmuv])
|
||||
cpu="sparc"
|
||||
supported_cpu="yes"
|
||||
;;
|
||||
*)
|
||||
# This will result in either an error or falling back to TCI later
|
||||
@@ -694,7 +696,10 @@ Linux)
|
||||
supported_os="yes"
|
||||
;;
|
||||
*)
|
||||
error_exit "Unsupported host OS $targetos"
|
||||
# This is a fatal error, but don't report it yet, because we
|
||||
# might be going to just print the --help text, or it might
|
||||
# be the result of a missing compiler.
|
||||
bogus_os="yes"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1460,6 +1465,14 @@ if ! compile_prog ; then
|
||||
error_exit "\"$cc\" cannot build an executable (is your linker broken?)"
|
||||
fi
|
||||
|
||||
if test "$bogus_os" = "yes"; then
|
||||
# Now that we know that we're not printing the help and that
|
||||
# the compiler works (so the results of the check_defines we used
|
||||
# to identify the OS are reliable), if we didn't recognize the
|
||||
# host OS we should stop now.
|
||||
error_exit "Unrecognized host OS $targetos"
|
||||
fi
|
||||
|
||||
# Check that the C++ compiler exists and works with the C compiler
|
||||
if has $cxx; then
|
||||
cat > $TMPC <<EOF
|
||||
@@ -3060,12 +3073,23 @@ fi
|
||||
##########################################
|
||||
# glib support probe
|
||||
|
||||
glib_req_ver=2.22
|
||||
if test "$mingw32" = yes; then
|
||||
glib_req_ver=2.30
|
||||
else
|
||||
glib_req_ver=2.22
|
||||
fi
|
||||
glib_modules=gthread-2.0
|
||||
if test "$modules" = yes; then
|
||||
glib_modules="$glib_modules gmodule-2.0"
|
||||
fi
|
||||
|
||||
# This workaround is required due to a bug in pkg-config file for glib as it
|
||||
# doesn't define GLIB_STATIC_COMPILATION for pkg-config --static
|
||||
|
||||
if test "$static" = yes -a "$mingw32" = yes; then
|
||||
QEMU_CFLAGS="-DGLIB_STATIC_COMPILATION $QEMU_CFLAGS"
|
||||
fi
|
||||
|
||||
for i in $glib_modules; do
|
||||
if $pkg_config --atleast-version=$glib_req_ver $i; then
|
||||
glib_cflags=$($pkg_config --cflags $i)
|
||||
|
||||
+7
-7
@@ -600,13 +600,13 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
/* Instruction counter expired. */
|
||||
assert(use_icount);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->icount_extra) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
cpu->icount_extra += insns_left;
|
||||
insns_left = MIN(0xffff, cpu->icount_extra);
|
||||
cpu->icount_extra -= insns_left;
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
} else {
|
||||
/* Ensure global icount has gone forward */
|
||||
cpu_update_icount(cpu);
|
||||
/* Refill decrementer and continue execution. */
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
if (!cpu->icount_extra) {
|
||||
/* Execute any remaining instructions, then let the main loop
|
||||
* handle the next event.
|
||||
*/
|
||||
|
||||
@@ -202,7 +202,7 @@ void qemu_tcg_configure(QemuOpts *opts, Error **errp)
|
||||
} else if (use_icount) {
|
||||
error_setg(errp, "No MTTCG when icount is enabled");
|
||||
} else {
|
||||
#ifndef TARGET_SUPPORT_MTTCG
|
||||
#ifndef TARGET_SUPPORTS_MTTCG
|
||||
error_report("Guest not yet converted to MTTCG - "
|
||||
"you may get unexpected results");
|
||||
#endif
|
||||
@@ -223,20 +223,51 @@ void qemu_tcg_configure(QemuOpts *opts, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
/* The current number of executed instructions is based on what we
|
||||
* originally budgeted minus the current state of the decrementing
|
||||
* icount counters in extra/u16.low.
|
||||
*/
|
||||
static int64_t cpu_get_icount_executed(CPUState *cpu)
|
||||
{
|
||||
return cpu->icount_budget - (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the global shared timer_state.qemu_icount to take into
|
||||
* account executed instructions. This is done by the TCG vCPU
|
||||
* thread so the main-loop can see time has moved forward.
|
||||
*/
|
||||
void cpu_update_icount(CPUState *cpu)
|
||||
{
|
||||
int64_t executed = cpu_get_icount_executed(cpu);
|
||||
cpu->icount_budget -= executed;
|
||||
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
atomic_set__nocheck(&timers_state.qemu_icount,
|
||||
atomic_read__nocheck(&timers_state.qemu_icount) +
|
||||
executed);
|
||||
#else /* FIXME: we need 64bit atomics to do this safely */
|
||||
timers_state.qemu_icount += executed;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t cpu_get_icount_raw(void)
|
||||
{
|
||||
int64_t icount;
|
||||
CPUState *cpu = current_cpu;
|
||||
|
||||
icount = timers_state.qemu_icount;
|
||||
if (cpu) {
|
||||
if (cpu && cpu->running) {
|
||||
if (!cpu->can_do_io) {
|
||||
fprintf(stderr, "Bad icount read\n");
|
||||
exit(1);
|
||||
}
|
||||
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
|
||||
/* Take into account what has run */
|
||||
cpu_update_icount(cpu);
|
||||
}
|
||||
return icount;
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
return atomic_read__nocheck(&timers_state.qemu_icount);
|
||||
#else /* FIXME: we need 64bit atomics to do this safely */
|
||||
return timers_state.qemu_icount;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the virtual CPU time, based on the instruction counter. */
|
||||
@@ -1179,6 +1210,41 @@ static void handle_icount_deadline(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_icount_for_run(CPUState *cpu)
|
||||
{
|
||||
if (use_icount) {
|
||||
int insns_left;
|
||||
|
||||
/* These should always be cleared by process_icount_data after
|
||||
* each vCPU execution. However u16.high can be raised
|
||||
* asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
|
||||
*/
|
||||
g_assert(cpu->icount_decr.u16.low == 0);
|
||||
g_assert(cpu->icount_extra == 0);
|
||||
|
||||
cpu->icount_budget = tcg_get_icount_limit();
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_icount_data(CPUState *cpu)
|
||||
{
|
||||
if (use_icount) {
|
||||
/* Account for executed instructions */
|
||||
cpu_update_icount(cpu);
|
||||
|
||||
/* Reset the counters */
|
||||
cpu->icount_decr.u16.low = 0;
|
||||
cpu->icount_extra = 0;
|
||||
cpu->icount_budget = 0;
|
||||
|
||||
replay_account_executed_instructions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int tcg_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
int ret;
|
||||
@@ -1189,20 +1255,6 @@ static int tcg_cpu_exec(CPUState *cpu)
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
if (use_icount) {
|
||||
int64_t count;
|
||||
int decr;
|
||||
timers_state.qemu_icount -= (cpu->icount_decr.u16.low
|
||||
+ cpu->icount_extra);
|
||||
cpu->icount_decr.u16.low = 0;
|
||||
cpu->icount_extra = 0;
|
||||
count = tcg_get_icount_limit();
|
||||
timers_state.qemu_icount += count;
|
||||
decr = (count > 0xffff) ? 0xffff : count;
|
||||
count -= decr;
|
||||
cpu->icount_decr.u16.low = decr;
|
||||
cpu->icount_extra = count;
|
||||
}
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_start(cpu);
|
||||
ret = cpu_exec(cpu);
|
||||
@@ -1211,15 +1263,6 @@ static int tcg_cpu_exec(CPUState *cpu)
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_time += profile_getclock() - ti;
|
||||
#endif
|
||||
if (use_icount) {
|
||||
/* Fold pending instructions back into the
|
||||
instruction counter, and clear the interrupt flag. */
|
||||
timers_state.qemu_icount -= (cpu->icount_decr.u16.low
|
||||
+ cpu->icount_extra);
|
||||
cpu->icount_decr.u32 = 0;
|
||||
cpu->icount_extra = 0;
|
||||
replay_account_executed_instructions();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1306,7 +1349,13 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
|
||||
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
|
||||
prepare_icount_for_run(cpu);
|
||||
|
||||
r = tcg_cpu_exec(cpu);
|
||||
|
||||
process_icount_data(cpu);
|
||||
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
break;
|
||||
@@ -1392,6 +1441,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
g_assert(!use_icount);
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
@@ -1434,8 +1485,6 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
handle_icount_deadline();
|
||||
|
||||
atomic_mb_set(&cpu->exit_request, 0);
|
||||
qemu_tcg_wait_io_event(cpu);
|
||||
}
|
||||
|
||||
+2
-2
@@ -2048,7 +2048,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
{
|
||||
/* We're looking at [pc+], i.e. we need to output an immediate
|
||||
number, where the size can depend on different things. */
|
||||
long number;
|
||||
int32_t number;
|
||||
int signedp
|
||||
= ((*cs == 'z' && (insn & 0x20))
|
||||
|| opcodep->match == BDAP_QUICK_OPCODE);
|
||||
@@ -2290,7 +2290,7 @@ print_with_operands (const struct cris_opcode *opcodep,
|
||||
|
||||
if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
|
||||
{
|
||||
long number;
|
||||
int32_t number;
|
||||
unsigned int nbytes;
|
||||
|
||||
/* It's a value. Get its size. */
|
||||
|
||||
@@ -3236,75 +3236,33 @@ int64_t address_space_cache_init(MemoryRegionCache *cache,
|
||||
hwaddr len,
|
||||
bool is_write)
|
||||
{
|
||||
hwaddr l, xlat;
|
||||
MemoryRegion *mr;
|
||||
void *ptr;
|
||||
|
||||
assert(len > 0);
|
||||
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
l = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, &l);
|
||||
|
||||
cache->xlat = xlat;
|
||||
cache->is_write = is_write;
|
||||
cache->mr = mr;
|
||||
cache->ptr = ptr;
|
||||
cache->len = l;
|
||||
memory_region_ref(cache->mr);
|
||||
|
||||
return l;
|
||||
cache->len = len;
|
||||
cache->as = as;
|
||||
cache->xlat = addr;
|
||||
return len;
|
||||
}
|
||||
|
||||
void address_space_cache_invalidate(MemoryRegionCache *cache,
|
||||
hwaddr addr,
|
||||
hwaddr access_len)
|
||||
{
|
||||
assert(cache->is_write);
|
||||
invalidate_and_set_dirty(cache->mr, addr + cache->xlat, access_len);
|
||||
}
|
||||
|
||||
void address_space_cache_destroy(MemoryRegionCache *cache)
|
||||
{
|
||||
if (!cache->mr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (xen_enabled()) {
|
||||
xen_invalidate_map_cache_entry(cache->ptr);
|
||||
}
|
||||
memory_region_unref(cache->mr);
|
||||
cache->mr = NULL;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section. This function has the same
|
||||
* semantics as address_space_translate, but it only works on a
|
||||
* predefined range of a MemoryRegion that was mapped with
|
||||
* address_space_cache_init.
|
||||
*/
|
||||
static inline MemoryRegion *address_space_translate_cached(
|
||||
MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *plen, bool is_write)
|
||||
{
|
||||
assert(addr < cache->len && *plen <= cache->len - addr);
|
||||
*xlat = addr + cache->xlat;
|
||||
return cache->mr;
|
||||
cache->as = NULL;
|
||||
}
|
||||
|
||||
#define ARG1_DECL MemoryRegionCache *cache
|
||||
#define ARG1 cache
|
||||
#define SUFFIX _cached
|
||||
#define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__)
|
||||
#define TRANSLATE(addr, ...) \
|
||||
address_space_translate(cache->as, cache->xlat + (addr), __VA_ARGS__)
|
||||
#define IS_DIRECT(mr, is_write) true
|
||||
#define MAP_RAM(mr, ofs) (cache->ptr + (ofs - cache->xlat))
|
||||
#define INVALIDATE(mr, ofs, len) ((void)0)
|
||||
#define RCU_READ_LOCK() ((void)0)
|
||||
#define RCU_READ_UNLOCK() ((void)0)
|
||||
#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->ram_block, ofs)
|
||||
#define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len)
|
||||
#define RCU_READ_LOCK() rcu_read_lock()
|
||||
#define RCU_READ_UNLOCK() rcu_read_unlock()
|
||||
#include "memory_ldst.inc.c"
|
||||
|
||||
/* virtual memory access for debug (includes writing to ROM) */
|
||||
|
||||
+6
-1
@@ -1098,8 +1098,13 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||
{
|
||||
if (dir_path) {
|
||||
v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
|
||||
} else {
|
||||
} else if (strcmp(name, "/")) {
|
||||
v9fs_path_sprintf(target, "%s", name);
|
||||
} else {
|
||||
/* We want the path of the export root to be relative, otherwise
|
||||
* "*at()" syscalls would treat it as "/" in the host.
|
||||
*/
|
||||
v9fs_path_sprintf(target, "%s", ".");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
||||
g_free(name);
|
||||
close_preserve_errno(dirfd);
|
||||
if (xattr_len < 0) {
|
||||
g_free(orig_value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -539,14 +539,15 @@ static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
|
||||
|
||||
/* Free all fids */
|
||||
while (s->fid_list) {
|
||||
/* Get fid */
|
||||
fidp = s->fid_list;
|
||||
s->fid_list = fidp->next;
|
||||
fidp->ref++;
|
||||
|
||||
if (fidp->ref) {
|
||||
fidp->clunked = 1;
|
||||
} else {
|
||||
free_fid(pdu, fidp);
|
||||
}
|
||||
/* Clunk fid */
|
||||
s->fid_list = fidp->next;
|
||||
fidp->clunked = 1;
|
||||
|
||||
put_fid(pdu, fidp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2387,8 +2388,10 @@ static void coroutine_fn v9fs_flush(void *opaque)
|
||||
* Wait for pdu to complete.
|
||||
*/
|
||||
qemu_co_queue_wait(&cancel_pdu->complete, NULL);
|
||||
cancel_pdu->cancelled = 0;
|
||||
pdu_free(cancel_pdu);
|
||||
if (!qemu_co_queue_next(&cancel_pdu->complete)) {
|
||||
cancel_pdu->cancelled = 0;
|
||||
pdu_free(cancel_pdu);
|
||||
}
|
||||
}
|
||||
pdu_complete(pdu, 7);
|
||||
}
|
||||
|
||||
@@ -75,8 +75,6 @@ static void tco_timer_expired(void *opaque)
|
||||
|
||||
if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) {
|
||||
ich9_generate_smi();
|
||||
} else {
|
||||
ich9_generate_nmi();
|
||||
}
|
||||
tr->tco.rld = tr->tco.tmr;
|
||||
tco_timer_reload(tr);
|
||||
|
||||
@@ -124,8 +124,12 @@ static void release_drive(Object *obj, const char *name, void *opaque)
|
||||
BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
||||
if (*ptr) {
|
||||
AioContext *ctx = blk_get_aio_context(*ptr);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
blockdev_auto_del(*ptr);
|
||||
blk_detach_dev(*ptr, dev);
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "migration/migration.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "qxl.h"
|
||||
@@ -639,6 +640,30 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
qxl->guest_primary.commands++;
|
||||
qxl_track_command(qxl, ext);
|
||||
qxl_log_command(qxl, "cmd", ext);
|
||||
{
|
||||
/*
|
||||
* Windows 8 drivers place qxl commands in the vram
|
||||
* (instead of the ram) bar. We can't live migrate such a
|
||||
* guest, so add a migration blocker in case we detect
|
||||
* this, to avoid triggering the assert in pre_save().
|
||||
*
|
||||
* https://cgit.freedesktop.org/spice/win32/qxl-wddm-dod/commit/?id=f6e099db39e7d0787f294d5fd0dce328b5210faa
|
||||
*/
|
||||
void *msg = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
|
||||
if (msg != NULL && (
|
||||
msg < (void *)qxl->vga.vram_ptr ||
|
||||
msg > ((void *)qxl->vga.vram_ptr + qxl->vga.vram_size))) {
|
||||
if (!qxl->migration_blocker) {
|
||||
Error *local_err = NULL;
|
||||
error_setg(&qxl->migration_blocker,
|
||||
"qxl: guest bug: command not in ram bar");
|
||||
migrate_add_blocker(qxl->migration_blocker, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
|
||||
return true;
|
||||
default:
|
||||
@@ -1146,6 +1171,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
|
||||
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
|
||||
qemu_spice_create_host_primary(&d->ssd);
|
||||
d->mode = QXL_MODE_VGA;
|
||||
qemu_spice_display_switch(&d->ssd, d->ssd.ds);
|
||||
vga_dirty_log_start(&d->vga);
|
||||
graphic_hw_update(d->vga.con);
|
||||
}
|
||||
@@ -1235,6 +1261,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
|
||||
qemu_spice_create_host_memslot(&d->ssd);
|
||||
qxl_soft_reset(d);
|
||||
|
||||
if (d->migration_blocker) {
|
||||
migrate_del_blocker(d->migration_blocker);
|
||||
error_free(d->migration_blocker);
|
||||
d->migration_blocker = NULL;
|
||||
}
|
||||
|
||||
if (startstop) {
|
||||
qemu_spice_display_start();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef struct PCIQXLDevice {
|
||||
uint32_t cmdlog;
|
||||
|
||||
uint32_t guest_bug;
|
||||
Error *migration_blocker;
|
||||
|
||||
enum qxl_mode mode;
|
||||
uint32_t cmdflags;
|
||||
|
||||
+11
-6
@@ -614,12 +614,6 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
s = c->gic;
|
||||
cpu = ARM_CPU(c->cpu);
|
||||
|
||||
/* Initialize to actual HW supported configuration */
|
||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
||||
KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
|
||||
&c->icc_ctlr_el1[GICV3_NS], false);
|
||||
|
||||
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
|
||||
c->icc_pmr_el1 = 0;
|
||||
c->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
|
||||
c->icc_bpr[GICV3_G1] = GIC_MIN_BPR;
|
||||
@@ -628,6 +622,17 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
c->icc_sre_el1 = 0x7;
|
||||
memset(c->icc_apr, 0, sizeof(c->icc_apr));
|
||||
memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen));
|
||||
|
||||
if (s->migration_blocker) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize to actual HW supported configuration */
|
||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
||||
KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
|
||||
&c->icc_ctlr_el1[GICV3_NS], false);
|
||||
|
||||
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
|
||||
}
|
||||
|
||||
static void kvm_arm_gicv3_reset(DeviceState *dev)
|
||||
|
||||
+12
-22
@@ -37,40 +37,30 @@
|
||||
#define IPMI_BT_HBUSY_BIT 6
|
||||
#define IPMI_BT_BBUSY_BIT 7
|
||||
|
||||
#define IPMI_BT_CLR_WR_MASK (1 << IPMI_BT_CLR_WR_BIT)
|
||||
#define IPMI_BT_GET_CLR_WR(d) (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_CLR_WR(d, v) (d) = (((d) & ~IPMI_BT_CLR_WR_MASK) | \
|
||||
(((v & 1) << IPMI_BT_CLR_WR_BIT)))
|
||||
|
||||
#define IPMI_BT_CLR_RD_MASK (1 << IPMI_BT_CLR_RD_BIT)
|
||||
#define IPMI_BT_GET_CLR_RD(d) (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_CLR_RD(d, v) (d) = (((d) & ~IPMI_BT_CLR_RD_MASK) | \
|
||||
(((v & 1) << IPMI_BT_CLR_RD_BIT)))
|
||||
|
||||
#define IPMI_BT_H2B_ATN_MASK (1 << IPMI_BT_H2B_ATN_BIT)
|
||||
#define IPMI_BT_GET_H2B_ATN(d) (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_H2B_ATN(d, v) (d) = (((d) & ~IPMI_BT_H2B_ATN_MASK) | \
|
||||
(((v & 1) << IPMI_BT_H2B_ATN_BIT)))
|
||||
|
||||
#define IPMI_BT_B2H_ATN_MASK (1 << IPMI_BT_B2H_ATN_BIT)
|
||||
#define IPMI_BT_GET_B2H_ATN(d) (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_B2H_ATN(d, v) (d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
|
||||
(((v & 1) << IPMI_BT_B2H_ATN_BIT)))
|
||||
#define IPMI_BT_SET_B2H_ATN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
|
||||
(((v) & 1) << IPMI_BT_B2H_ATN_BIT)))
|
||||
|
||||
#define IPMI_BT_SMS_ATN_MASK (1 << IPMI_BT_SMS_ATN_BIT)
|
||||
#define IPMI_BT_GET_SMS_ATN(d) (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_SMS_ATN(d, v) (d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
|
||||
(((v & 1) << IPMI_BT_SMS_ATN_BIT)))
|
||||
#define IPMI_BT_SET_SMS_ATN(d, v) ((d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
|
||||
(((v) & 1) << IPMI_BT_SMS_ATN_BIT)))
|
||||
|
||||
#define IPMI_BT_HBUSY_MASK (1 << IPMI_BT_HBUSY_BIT)
|
||||
#define IPMI_BT_GET_HBUSY(d) (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_HBUSY(d, v) (d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
|
||||
(((v & 1) << IPMI_BT_HBUSY_BIT)))
|
||||
#define IPMI_BT_SET_HBUSY(d, v) ((d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
|
||||
(((v) & 1) << IPMI_BT_HBUSY_BIT)))
|
||||
|
||||
#define IPMI_BT_BBUSY_MASK (1 << IPMI_BT_BBUSY_BIT)
|
||||
#define IPMI_BT_GET_BBUSY(d) (((d) >> IPMI_BT_BBUSY_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_BBUSY(d, v) (d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
|
||||
(((v & 1) << IPMI_BT_BBUSY_BIT)))
|
||||
#define IPMI_BT_SET_BBUSY(d, v) ((d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
|
||||
(((v) & 1) << IPMI_BT_BBUSY_BIT)))
|
||||
|
||||
|
||||
/* Mask register */
|
||||
@@ -79,13 +69,13 @@
|
||||
|
||||
#define IPMI_BT_B2H_IRQ_EN_MASK (1 << IPMI_BT_B2H_IRQ_EN_BIT)
|
||||
#define IPMI_BT_GET_B2H_IRQ_EN(d) (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_B2H_IRQ_EN(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) | \
|
||||
(((v & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
|
||||
#define IPMI_BT_SET_B2H_IRQ_EN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) |\
|
||||
(((v) & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
|
||||
|
||||
#define IPMI_BT_B2H_IRQ_MASK (1 << IPMI_BT_B2H_IRQ_BIT)
|
||||
#define IPMI_BT_GET_B2H_IRQ(d) (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
|
||||
#define IPMI_BT_SET_B2H_IRQ(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
|
||||
(((v & 1) << IPMI_BT_B2H_IRQ_BIT)))
|
||||
#define IPMI_BT_SET_B2H_IRQ(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
|
||||
(((v) & 1) << IPMI_BT_B2H_IRQ_BIT)))
|
||||
|
||||
typedef struct IPMIBT {
|
||||
IPMIBmc *bmc;
|
||||
|
||||
@@ -312,11 +312,6 @@ void ich9_generate_smi(void)
|
||||
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
|
||||
}
|
||||
|
||||
void ich9_generate_nmi(void)
|
||||
{
|
||||
cpu_interrupt(first_cpu, CPU_INTERRUPT_NMI);
|
||||
}
|
||||
|
||||
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
|
||||
{
|
||||
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@
|
||||
|
||||
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
#define E1000_DEBUG
|
||||
/* #define E1000_DEBUG */
|
||||
|
||||
#ifdef E1000_DEBUG
|
||||
enum {
|
||||
|
||||
@@ -510,6 +510,10 @@ static int peer_attach(VirtIONet *n, int index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n->max_queues == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tap_enable(nc->peer);
|
||||
}
|
||||
|
||||
|
||||
@@ -869,6 +869,10 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
|
||||
pci_dev->bus->devices[pci_dev->devfn] = NULL;
|
||||
pci_config_free(pci_dev);
|
||||
|
||||
if (memory_region_is_mapped(&pci_dev->bus_master_enable_region)) {
|
||||
memory_region_del_subregion(&pci_dev->bus_master_container_region,
|
||||
&pci_dev->bus_master_enable_region);
|
||||
}
|
||||
address_space_destroy(&pci_dev->bus_master_as);
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -1524,16 +1524,16 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
/* Consume invalid HPTEs */
|
||||
while ((index < htabslots)
|
||||
&& !HPTE_VALID(HPTE(spapr->htab, index))) {
|
||||
index++;
|
||||
CLEAN_HPTE(HPTE(spapr->htab, index));
|
||||
index++;
|
||||
}
|
||||
|
||||
/* Consume valid HPTEs */
|
||||
chunkstart = index;
|
||||
while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
|
||||
&& HPTE_VALID(HPTE(spapr->htab, index))) {
|
||||
index++;
|
||||
CLEAN_HPTE(HPTE(spapr->htab, index));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index > chunkstart) {
|
||||
@@ -2790,6 +2790,12 @@ static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cc->nr_threads != smp_threads) {
|
||||
error_setg(errp, "invalid nr-threads %d, must be %d",
|
||||
cc->nr_threads, smp_threads);
|
||||
return;
|
||||
}
|
||||
|
||||
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
|
||||
if (!core_slot) {
|
||||
error_setg(&local_err, "core id %d out of range", cc->core_id);
|
||||
|
||||
+17
-3
@@ -135,6 +135,17 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
|
||||
if (!drc->dev) {
|
||||
return RTAS_OUT_NO_SUCH_INDICATOR;
|
||||
}
|
||||
if (drc->awaiting_release && drc->awaiting_allocation) {
|
||||
/* kernel is acknowledging a previous hotplug event
|
||||
* while we are already removing it.
|
||||
* it's safe to ignore awaiting_allocation here since we know the
|
||||
* situation is predicated on the guest either already having done
|
||||
* so (boot-time hotplug), or never being able to acquire in the
|
||||
* first place (hotplug followed by immediate unplug).
|
||||
*/
|
||||
drc->awaiting_allocation_skippable = true;
|
||||
return RTAS_OUT_NO_SUCH_INDICATOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
|
||||
@@ -436,9 +447,11 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
|
||||
}
|
||||
|
||||
if (drc->awaiting_allocation) {
|
||||
drc->awaiting_release = true;
|
||||
trace_spapr_drc_awaiting_allocation(get_index(drc));
|
||||
return;
|
||||
if (!drc->awaiting_allocation_skippable) {
|
||||
drc->awaiting_release = true;
|
||||
trace_spapr_drc_awaiting_allocation(get_index(drc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
|
||||
@@ -448,6 +461,7 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
|
||||
}
|
||||
|
||||
drc->awaiting_release = false;
|
||||
drc->awaiting_allocation_skippable = false;
|
||||
g_free(drc->fdt);
|
||||
drc->fdt = NULL;
|
||||
drc->fdt_start_offset = 0;
|
||||
|
||||
+3
-1
@@ -2063,7 +2063,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||
static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
|
||||
{
|
||||
XHCIState *xhci = epctx->xhci;
|
||||
XHCIStreamContext *stctx;
|
||||
XHCIStreamContext *stctx = NULL;
|
||||
XHCITransfer *xfer;
|
||||
XHCIRing *ring;
|
||||
USBEndpoint *ep = NULL;
|
||||
@@ -2186,6 +2186,8 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* update ring dequeue ptr */
|
||||
xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
|
||||
epctx->kick_active--;
|
||||
|
||||
ep = xhci_epid_to_usbep(epctx);
|
||||
|
||||
@@ -159,7 +159,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
|
||||
#define BULK_TIMEOUT 0 /* unlimited */
|
||||
#define INTR_TIMEOUT 0 /* unlimited */
|
||||
|
||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||
#ifndef LIBUSB_API_VERSION
|
||||
# define LIBUSB_API_VERSION LIBUSBX_API_VERSION
|
||||
#endif
|
||||
#if LIBUSB_API_VERSION >= 0x01000103
|
||||
# define HAVE_STREAMS 1
|
||||
#endif
|
||||
|
||||
@@ -269,7 +272,7 @@ static int usb_host_get_port(libusb_device *dev, char *port, size_t len)
|
||||
size_t off;
|
||||
int rc, i;
|
||||
|
||||
#if LIBUSBX_API_VERSION >= 0x01000102
|
||||
#if LIBUSB_API_VERSION >= 0x01000102
|
||||
rc = libusb_get_port_numbers(dev, path, 7);
|
||||
#else
|
||||
rc = libusb_get_port_path(ctx, dev, path, 7);
|
||||
|
||||
+29
-40
@@ -660,7 +660,7 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
VFIOConfigWindowQuirk *window;
|
||||
|
||||
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) ||
|
||||
!vdev->vga || nr != 5) {
|
||||
!vdev->vga || nr != 5 || !vdev->bars[5].ioport) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1367,45 +1367,14 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
uint16_t cmd_orig, cmd;
|
||||
Error *err = NULL;
|
||||
|
||||
/* This must be an Intel VGA device. */
|
||||
/*
|
||||
* This must be an Intel VGA device at address 00:02.0 for us to even
|
||||
* consider enabling legacy mode. The vBIOS has dependencies on the
|
||||
* PCI bus address.
|
||||
*/
|
||||
if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
|
||||
!vfio_is_vga(vdev) || nr != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IGD is not a standard, they like to change their specs often. We
|
||||
* only attempt to support back to SandBridge and we hope that newer
|
||||
* devices maintain compatibility with generation 8.
|
||||
*/
|
||||
gen = igd_gen(vdev);
|
||||
if (gen != 6 && gen != 8) {
|
||||
error_report("IGD device %s is unsupported by IGD quirks, "
|
||||
"try SandyBridge or newer", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Regardless of running in UPT or legacy mode, the guest graphics
|
||||
* driver may attempt to use stolen memory, however only legacy mode
|
||||
* has BIOS support for reserving stolen memory in the guest VM.
|
||||
* Emulate the GMCH register in all cases and zero out the stolen
|
||||
* memory size here. Legacy mode may request allocation and re-write
|
||||
* this below.
|
||||
*/
|
||||
gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
|
||||
gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
|
||||
|
||||
/* GMCH is read-only, emulated */
|
||||
pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
|
||||
pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
|
||||
pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
|
||||
|
||||
/*
|
||||
* This must be at address 00:02.0 for us to even onsider enabling
|
||||
* legacy mode. The vBIOS has dependencies on the PCI bus address.
|
||||
*/
|
||||
if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
|
||||
!vfio_is_vga(vdev) || nr != 4 ||
|
||||
&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
|
||||
0, PCI_DEVFN(0x2, 0))) {
|
||||
return;
|
||||
}
|
||||
@@ -1424,6 +1393,18 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IGD is not a standard, they like to change their specs often. We
|
||||
* only attempt to support back to SandBridge and we hope that newer
|
||||
* devices maintain compatibility with generation 8.
|
||||
*/
|
||||
gen = igd_gen(vdev);
|
||||
if (gen != 6 && gen != 8) {
|
||||
error_report("IGD device %s is unsupported in legacy mode, "
|
||||
"try SandyBridge or newer", vdev->vbasedev.name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Most of what we're doing here is to enable the ROM to run, so if
|
||||
* there's no ROM, there's no point in setting up this quirk.
|
||||
@@ -1479,6 +1460,8 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
goto out;
|
||||
}
|
||||
|
||||
gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
|
||||
|
||||
/*
|
||||
* If IGD VGA Disable is clear (expected) and VGA is not already enabled,
|
||||
* try to enable it. Probably shouldn't be using legacy mode without VGA,
|
||||
@@ -1549,11 +1532,12 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
* when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
|
||||
* so let's not waste VM memory for it.
|
||||
*/
|
||||
gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
|
||||
|
||||
if (vdev->igd_gms) {
|
||||
if (vdev->igd_gms <= 0x10) {
|
||||
gms_mb = vdev->igd_gms * 32;
|
||||
gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8);
|
||||
pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
|
||||
} else {
|
||||
error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
|
||||
vdev->igd_gms = 0;
|
||||
@@ -1573,6 +1557,11 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
|
||||
bdsm_size, sizeof(*bdsm_size));
|
||||
|
||||
/* GMCH is read-only, emulated */
|
||||
pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
|
||||
pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
|
||||
pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
|
||||
|
||||
/* BDSM is read-write, emulated. The BIOS needs to be able to write it */
|
||||
pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
|
||||
pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
|
||||
|
||||
+64
-20
@@ -425,10 +425,8 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
|
||||
static int vhost_dev_has_iommu(struct vhost_dev *dev)
|
||||
{
|
||||
VirtIODevice *vdev = dev->vdev;
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
return memory_region_is_iommu(dma_as->root) &&
|
||||
virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
|
||||
return virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
|
||||
}
|
||||
|
||||
static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr,
|
||||
@@ -720,6 +718,63 @@ static void vhost_region_del(MemoryListener *listener,
|
||||
}
|
||||
}
|
||||
|
||||
static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
|
||||
{
|
||||
struct vhost_iommu *iommu = container_of(n, struct vhost_iommu, n);
|
||||
struct vhost_dev *hdev = iommu->hdev;
|
||||
hwaddr iova = iotlb->iova + iommu->iommu_offset;
|
||||
|
||||
if (hdev->vhost_ops->vhost_invalidate_device_iotlb(hdev, iova,
|
||||
iotlb->addr_mask + 1)) {
|
||||
error_report("Fail to invalidate device iotlb");
|
||||
}
|
||||
}
|
||||
|
||||
static void vhost_iommu_region_add(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
struct vhost_dev *dev = container_of(listener, struct vhost_dev,
|
||||
iommu_listener);
|
||||
struct vhost_iommu *iommu;
|
||||
|
||||
if (!memory_region_is_iommu(section->mr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
iommu = g_malloc0(sizeof(*iommu));
|
||||
iommu->n.notify = vhost_iommu_unmap_notify;
|
||||
iommu->n.notifier_flags = IOMMU_NOTIFIER_UNMAP;
|
||||
iommu->mr = section->mr;
|
||||
iommu->iommu_offset = section->offset_within_address_space -
|
||||
section->offset_within_region;
|
||||
iommu->hdev = dev;
|
||||
memory_region_register_iommu_notifier(section->mr, &iommu->n);
|
||||
QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next);
|
||||
/* TODO: can replay help performance here? */
|
||||
}
|
||||
|
||||
static void vhost_iommu_region_del(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
struct vhost_dev *dev = container_of(listener, struct vhost_dev,
|
||||
iommu_listener);
|
||||
struct vhost_iommu *iommu;
|
||||
|
||||
if (!memory_region_is_iommu(section->mr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) {
|
||||
if (iommu->mr == section->mr) {
|
||||
memory_region_unregister_iommu_notifier(iommu->mr,
|
||||
&iommu->n);
|
||||
QLIST_REMOVE(iommu, iommu_next);
|
||||
g_free(iommu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vhost_region_nop(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
@@ -1161,17 +1216,6 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
|
||||
event_notifier_cleanup(&vq->masked_notifier);
|
||||
}
|
||||
|
||||
static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
|
||||
{
|
||||
struct vhost_dev *hdev = container_of(n, struct vhost_dev, n);
|
||||
|
||||
if (hdev->vhost_ops->vhost_invalidate_device_iotlb(hdev,
|
||||
iotlb->iova,
|
||||
iotlb->addr_mask + 1)) {
|
||||
error_report("Fail to invalidate device iotlb");
|
||||
}
|
||||
}
|
||||
|
||||
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
VhostBackendType backend_type, uint32_t busyloop_timeout)
|
||||
{
|
||||
@@ -1244,8 +1288,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
.priority = 10
|
||||
};
|
||||
|
||||
hdev->n.notify = vhost_iommu_unmap_notify;
|
||||
hdev->n.notifier_flags = IOMMU_NOTIFIER_UNMAP;
|
||||
hdev->iommu_listener = (MemoryListener) {
|
||||
.region_add = vhost_iommu_region_add,
|
||||
.region_del = vhost_iommu_region_del,
|
||||
};
|
||||
|
||||
if (hdev->migration_blocker == NULL) {
|
||||
if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
|
||||
@@ -1455,8 +1501,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
}
|
||||
|
||||
if (vhost_dev_has_iommu(hdev)) {
|
||||
memory_region_register_iommu_notifier(vdev->dma_as->root,
|
||||
&hdev->n);
|
||||
memory_listener_register(&hdev->iommu_listener, vdev->dma_as);
|
||||
}
|
||||
|
||||
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
|
||||
@@ -1538,8 +1583,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
|
||||
if (vhost_dev_has_iommu(hdev)) {
|
||||
hdev->vhost_ops->vhost_set_iotlb_callback(hdev, false);
|
||||
memory_region_unregister_iommu_notifier(vdev->dma_as->root,
|
||||
&hdev->n);
|
||||
memory_listener_unregister(&hdev->iommu_listener);
|
||||
}
|
||||
vhost_log_put(hdev, true);
|
||||
hdev->started = false;
|
||||
|
||||
@@ -510,6 +510,15 @@ void aio_co_schedule(AioContext *ctx, struct Coroutine *co);
|
||||
*/
|
||||
void aio_co_wake(struct Coroutine *co);
|
||||
|
||||
/**
|
||||
* aio_co_enter:
|
||||
* @ctx: the context to run the coroutine
|
||||
* @co: the coroutine to run
|
||||
*
|
||||
* Enter a coroutine in the specified AioContext.
|
||||
*/
|
||||
void aio_co_enter(AioContext *ctx, struct Coroutine *co);
|
||||
|
||||
/**
|
||||
* Return the AioContext whose event loop runs in the current thread.
|
||||
*
|
||||
|
||||
+37
-8
@@ -366,6 +366,8 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
|
||||
void bdrv_invalidate_cache_all(Error **errp);
|
||||
int bdrv_inactivate_all(void);
|
||||
|
||||
void blk_resume_after_migration(Error **errp);
|
||||
|
||||
/* Ensure contents are flushed to disk. */
|
||||
int bdrv_flush(BlockDriverState *bs);
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
|
||||
@@ -379,12 +381,13 @@ void bdrv_drain_all(void);
|
||||
|
||||
#define BDRV_POLL_WHILE(bs, cond) ({ \
|
||||
bool waited_ = false; \
|
||||
bool busy_ = true; \
|
||||
BlockDriverState *bs_ = (bs); \
|
||||
AioContext *ctx_ = bdrv_get_aio_context(bs_); \
|
||||
if (aio_context_in_iothread(ctx_)) { \
|
||||
while ((cond)) { \
|
||||
aio_poll(ctx_, true); \
|
||||
waited_ = true; \
|
||||
while ((cond) || busy_) { \
|
||||
busy_ = aio_poll(ctx_, (cond)); \
|
||||
waited_ |= !!(cond) | busy_; \
|
||||
} \
|
||||
} else { \
|
||||
assert(qemu_get_current_aio_context() == \
|
||||
@@ -396,11 +399,16 @@ void bdrv_drain_all(void);
|
||||
*/ \
|
||||
assert(!bs_->wakeup); \
|
||||
bs_->wakeup = true; \
|
||||
while ((cond)) { \
|
||||
aio_context_release(ctx_); \
|
||||
aio_poll(qemu_get_aio_context(), true); \
|
||||
aio_context_acquire(ctx_); \
|
||||
waited_ = true; \
|
||||
while (busy_) { \
|
||||
if ((cond)) { \
|
||||
waited_ = busy_ = true; \
|
||||
aio_context_release(ctx_); \
|
||||
aio_poll(qemu_get_aio_context(), true); \
|
||||
aio_context_acquire(ctx_); \
|
||||
} else { \
|
||||
busy_ = aio_poll(ctx_, false); \
|
||||
waited_ |= busy_; \
|
||||
} \
|
||||
} \
|
||||
bs_->wakeup = false; \
|
||||
} \
|
||||
@@ -555,6 +563,11 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
|
||||
*/
|
||||
AioContext *bdrv_get_aio_context(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* Transfer control to @co in the aio context of @bs
|
||||
*/
|
||||
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
|
||||
|
||||
/**
|
||||
* bdrv_set_aio_context:
|
||||
*
|
||||
@@ -570,6 +583,22 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
|
||||
void bdrv_io_plug(BlockDriverState *bs);
|
||||
void bdrv_io_unplug(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_parent_drained_begin:
|
||||
*
|
||||
* Begin a quiesced section of all users of @bs. This is part of
|
||||
* bdrv_drained_begin.
|
||||
*/
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_parent_drained_end:
|
||||
*
|
||||
* End a quiesced section of all users of @bs. This is part of
|
||||
* bdrv_drained_end.
|
||||
*/
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_drained_begin:
|
||||
*
|
||||
|
||||
@@ -1426,13 +1426,11 @@ void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val);
|
||||
|
||||
struct MemoryRegionCache {
|
||||
hwaddr xlat;
|
||||
void *ptr;
|
||||
hwaddr len;
|
||||
MemoryRegion *mr;
|
||||
bool is_write;
|
||||
AddressSpace *as;
|
||||
};
|
||||
|
||||
#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .mr = NULL })
|
||||
#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .as = NULL })
|
||||
|
||||
/* address_space_cache_init: prepare for repeated access to a physical
|
||||
* memory region
|
||||
@@ -1688,7 +1686,7 @@ address_space_read_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
void *buf, int len)
|
||||
{
|
||||
assert(addr < cache->len && len <= cache->len - addr);
|
||||
memcpy(buf, cache->ptr + addr, len);
|
||||
address_space_read(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1704,7 +1702,7 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
void *buf, int len)
|
||||
{
|
||||
assert(addr < cache->len && len <= cache->len - addr);
|
||||
memcpy(cache->ptr + addr, buf, len);
|
||||
address_space_write(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,6 @@ void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
|
||||
I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
|
||||
|
||||
void ich9_generate_smi(void);
|
||||
void ich9_generate_nmi(void);
|
||||
|
||||
#define ICH9_CC_SIZE (16 * 1024) /* 16KB. Chipset configuration registers */
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ typedef struct sPAPRDRConnector {
|
||||
bool awaiting_release;
|
||||
bool signalled;
|
||||
bool awaiting_allocation;
|
||||
bool awaiting_allocation_skippable;
|
||||
|
||||
/* device pointer, via link property */
|
||||
DeviceState *dev;
|
||||
|
||||
@@ -37,10 +37,20 @@ struct vhost_log {
|
||||
vhost_log_chunk_t *log;
|
||||
};
|
||||
|
||||
struct vhost_dev;
|
||||
struct vhost_iommu {
|
||||
struct vhost_dev *hdev;
|
||||
MemoryRegion *mr;
|
||||
hwaddr iommu_offset;
|
||||
IOMMUNotifier n;
|
||||
QLIST_ENTRY(vhost_iommu) iommu_next;
|
||||
};
|
||||
|
||||
struct vhost_memory;
|
||||
struct vhost_dev {
|
||||
VirtIODevice *vdev;
|
||||
MemoryListener memory_listener;
|
||||
MemoryListener iommu_listener;
|
||||
struct vhost_memory *mem;
|
||||
int n_mem_sections;
|
||||
MemoryRegionSection *mem_sections;
|
||||
@@ -64,6 +74,7 @@ struct vhost_dev {
|
||||
void *opaque;
|
||||
struct vhost_log *log;
|
||||
QLIST_ENTRY(vhost_dev) entry;
|
||||
QLIST_HEAD(, vhost_iommu) iommu_list;
|
||||
IOMMUNotifier n;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ struct VirtQueue;
|
||||
static inline hwaddr vring_align(hwaddr addr,
|
||||
unsigned long align)
|
||||
{
|
||||
return (addr + align - 1) & ~(align - 1);
|
||||
return QEMU_ALIGN_UP(addr, align);
|
||||
}
|
||||
|
||||
typedef struct VirtQueue VirtQueue;
|
||||
|
||||
@@ -76,6 +76,11 @@ void qemu_coroutine_enter(Coroutine *coroutine);
|
||||
*/
|
||||
void qemu_coroutine_enter_if_inactive(Coroutine *co);
|
||||
|
||||
/**
|
||||
* Transfer control to a coroutine and associate it with ctx
|
||||
*/
|
||||
void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co);
|
||||
|
||||
/**
|
||||
* Transfer control back to a coroutine's caller
|
||||
*
|
||||
|
||||
@@ -119,4 +119,15 @@ SocketAddress *socket_remote_address(int fd, Error **errp);
|
||||
*/
|
||||
char *socket_address_to_string(struct SocketAddress *addr, Error **errp);
|
||||
|
||||
/**
|
||||
* socket_address_crumple:
|
||||
* @addr_flat: the socket address to crumple
|
||||
*
|
||||
* Convert SocketAddressFlat to SocketAddress. Caller is responsible
|
||||
* for freeing with qapi_free_SocketAddress().
|
||||
*
|
||||
* Returns: the argument converted to SocketAddress.
|
||||
*/
|
||||
SocketAddress *socket_address_crumple(SocketAddressFlat *addr_flat);
|
||||
|
||||
#endif /* QEMU_SOCKETS_H */
|
||||
@@ -869,6 +869,7 @@ int64_t cpu_get_icount_raw(void);
|
||||
int64_t cpu_get_icount(void);
|
||||
int64_t cpu_get_clock(void);
|
||||
int64_t cpu_icount_to_ns(int64_t icount);
|
||||
void cpu_update_icount(CPUState *cpu);
|
||||
|
||||
/*******************************************/
|
||||
/* host CPU ticks (if available) */
|
||||
|
||||
@@ -332,6 +332,7 @@ struct CPUState {
|
||||
/* updates protected by BQL */
|
||||
uint32_t interrupt_request;
|
||||
int singlestep_enabled;
|
||||
int64_t icount_budget;
|
||||
int64_t icount_extra;
|
||||
sigjmp_buf jmp_env;
|
||||
|
||||
|
||||
+1
-7
@@ -331,16 +331,10 @@ qio_channel_socket_accept(QIOChannelSocket *ioc,
|
||||
{
|
||||
QIOChannelSocket *cioc;
|
||||
|
||||
cioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET));
|
||||
cioc->fd = -1;
|
||||
cioc = qio_channel_socket_new();
|
||||
cioc->remoteAddrLen = sizeof(ioc->remoteAddr);
|
||||
cioc->localAddrLen = sizeof(ioc->localAddr);
|
||||
|
||||
#ifdef WIN32
|
||||
QIO_CHANNEL(cioc)->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
retry:
|
||||
trace_qio_channel_socket_accept(ioc);
|
||||
cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr,
|
||||
|
||||
+2
-2
@@ -158,6 +158,7 @@ int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
|
||||
|
||||
case SOCKET_ADDRESS_KIND_UNIX:
|
||||
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
return qio_dns_resolver_lookup_sync_nop(resolver,
|
||||
addr,
|
||||
naddrs,
|
||||
@@ -165,8 +166,7 @@ int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
|
||||
errp);
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unknown socket address kind");
|
||||
return -1;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -349,6 +349,14 @@ static void process_incoming_migration_bh(void *opaque)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* If we get an error here, just don't restart the VM yet. */
|
||||
blk_resume_after_migration(&local_err);
|
||||
if (local_err) {
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
autostart = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This must happen after all error conditions are dealt with and
|
||||
* we're sure the VM is going to be running on this host.
|
||||
|
||||
+8
-11
@@ -4144,7 +4144,7 @@
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'enum': 'SocketAddressFlatType',
|
||||
'data': [ 'unix', 'inet' ] }
|
||||
'data': [ 'inet', 'unix', 'vsock', 'fd' ] }
|
||||
|
||||
##
|
||||
# @SocketAddressFlat:
|
||||
@@ -4153,22 +4153,19 @@
|
||||
#
|
||||
# @type: Transport type
|
||||
#
|
||||
# This is similar to SocketAddress, only distinction:
|
||||
#
|
||||
# 1. SocketAddressFlat is a flat union, SocketAddress is a simple union.
|
||||
# A flat union is nicer than simple because it avoids nesting
|
||||
# (i.e. more {}) on the wire.
|
||||
#
|
||||
# 2. SocketAddressFlat supports only types 'unix' and 'inet', because
|
||||
# that's what its current users need.
|
||||
# This is just like SocketAddress, except it's a flat union rather
|
||||
# than a simple union. Nicer because it avoids nesting on the wire,
|
||||
# i.e. this form has fewer {}.
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'union': 'SocketAddressFlat',
|
||||
'base': { 'type': 'SocketAddressFlatType' },
|
||||
'discriminator': 'type',
|
||||
'data': { 'unix': 'UnixSocketAddress',
|
||||
'inet': 'InetSocketAddress' } }
|
||||
'data': { 'inet': 'InetSocketAddress',
|
||||
'unix': 'UnixSocketAddress',
|
||||
'vsock': 'VsockSocketAddress',
|
||||
'fd': 'String' } }
|
||||
|
||||
##
|
||||
# @getfd:
|
||||
|
||||
+97
-12
@@ -2623,7 +2623,7 @@
|
||||
# Driver specific block device options for sheepdog
|
||||
#
|
||||
# @vdi: Virtual disk image name
|
||||
# @addr: The Sheepdog server to connect to
|
||||
# @server: The Sheepdog server to connect to
|
||||
# @snap-id: Snapshot ID
|
||||
# @tag: Snapshot tag name
|
||||
#
|
||||
@@ -2632,7 +2632,7 @@
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsSheepdog',
|
||||
'data': { 'addr': 'SocketAddressFlat',
|
||||
'data': { 'server': 'SocketAddressFlat',
|
||||
'vdi': 'str',
|
||||
'*snap-id': 'uint32',
|
||||
'*tag': 'str' } }
|
||||
@@ -2737,16 +2737,101 @@
|
||||
'*debug': 'int' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsCurl:
|
||||
# @BlockdevOptionsCurlBase:
|
||||
#
|
||||
# Driver specific block device options for the curl backend.
|
||||
# Driver specific block device options shared by all protocols supported by the
|
||||
# curl backend.
|
||||
#
|
||||
# @filename: path to the image file
|
||||
# @url: URL of the image file
|
||||
#
|
||||
# @readahead: Size of the read-ahead cache; must be a multiple of
|
||||
# 512 (defaults to 256 kB)
|
||||
#
|
||||
# @timeout: Timeout for connections, in seconds (defaults to 5)
|
||||
#
|
||||
# @username: Username for authentication (defaults to none)
|
||||
#
|
||||
# @password-secret: ID of a QCryptoSecret object providing a password
|
||||
# for authentication (defaults to no password)
|
||||
#
|
||||
# @proxy-username: Username for proxy authentication (defaults to none)
|
||||
#
|
||||
# @proxy-password-secret: ID of a QCryptoSecret object providing a password
|
||||
# for proxy authentication (defaults to no password)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsCurl',
|
||||
'data': { 'filename': 'str' } }
|
||||
{ 'struct': 'BlockdevOptionsCurlBase',
|
||||
'data': { 'url': 'str',
|
||||
'*readahead': 'int',
|
||||
'*timeout': 'int',
|
||||
'*username': 'str',
|
||||
'*password-secret': 'str',
|
||||
'*proxy-username': 'str',
|
||||
'*proxy-password-secret': 'str' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsCurlHttp:
|
||||
#
|
||||
# Driver specific block device options for HTTP connections over the curl
|
||||
# backend. URLs must start with "http://".
|
||||
#
|
||||
# @cookie: List of cookies to set; format is
|
||||
# "name1=content1; name2=content2;" as explained by
|
||||
# CURLOPT_COOKIE(3). Defaults to no cookies.
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsCurlHttp',
|
||||
'base': 'BlockdevOptionsCurlBase',
|
||||
'data': { '*cookie': 'str' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsCurlHttps:
|
||||
#
|
||||
# Driver specific block device options for HTTPS connections over the curl
|
||||
# backend. URLs must start with "https://".
|
||||
#
|
||||
# @cookie: List of cookies to set; format is
|
||||
# "name1=content1; name2=content2;" as explained by
|
||||
# CURLOPT_COOKIE(3). Defaults to no cookies.
|
||||
#
|
||||
# @sslverify: Whether to verify the SSL certificate's validity (defaults to
|
||||
# true)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsCurlHttps',
|
||||
'base': 'BlockdevOptionsCurlBase',
|
||||
'data': { '*cookie': 'str',
|
||||
'*sslverify': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsCurlFtp:
|
||||
#
|
||||
# Driver specific block device options for FTP connections over the curl
|
||||
# backend. URLs must start with "ftp://".
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsCurlFtp',
|
||||
'base': 'BlockdevOptionsCurlBase',
|
||||
'data': { } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsCurlFtps:
|
||||
#
|
||||
# Driver specific block device options for FTPS connections over the curl
|
||||
# backend. URLs must start with "ftps://".
|
||||
#
|
||||
# @sslverify: Whether to verify the SSL certificate's validity (defaults to
|
||||
# true)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsCurlFtps',
|
||||
'base': 'BlockdevOptionsCurlBase',
|
||||
'data': { '*sslverify': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsNbd:
|
||||
@@ -2762,7 +2847,7 @@
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsNbd',
|
||||
'data': { 'server': 'SocketAddress',
|
||||
'data': { 'server': 'SocketAddressFlat',
|
||||
'*export': 'str',
|
||||
'*tls-creds': 'str' } }
|
||||
|
||||
@@ -2815,13 +2900,13 @@
|
||||
'cloop': 'BlockdevOptionsGenericFormat',
|
||||
'dmg': 'BlockdevOptionsGenericFormat',
|
||||
'file': 'BlockdevOptionsFile',
|
||||
'ftp': 'BlockdevOptionsCurl',
|
||||
'ftps': 'BlockdevOptionsCurl',
|
||||
'ftp': 'BlockdevOptionsCurlFtp',
|
||||
'ftps': 'BlockdevOptionsCurlFtps',
|
||||
'gluster': 'BlockdevOptionsGluster',
|
||||
'host_cdrom': 'BlockdevOptionsFile',
|
||||
'host_device':'BlockdevOptionsFile',
|
||||
'http': 'BlockdevOptionsCurl',
|
||||
'https': 'BlockdevOptionsCurl',
|
||||
'http': 'BlockdevOptionsCurlHttp',
|
||||
'https': 'BlockdevOptionsCurlHttps',
|
||||
'iscsi': 'BlockdevOptionsIscsi',
|
||||
'luks': 'BlockdevOptionsLUKS',
|
||||
'nbd': 'BlockdevOptionsNbd',
|
||||
|
||||
+2
-2
@@ -22,9 +22,9 @@ STEXI
|
||||
ETEXI
|
||||
|
||||
DEF("create", img_create,
|
||||
"create [-q] [--object objectdef] [--image-opts] [-f fmt] [-o options] filename [size]")
|
||||
"create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]")
|
||||
STEXI
|
||||
@item create [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
|
||||
@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
|
||||
ETEXI
|
||||
|
||||
DEF("commit", img_commit,
|
||||
|
||||
+8
-1
@@ -35,6 +35,13 @@ static int compare_cmdname(const void *a, const void *b)
|
||||
|
||||
void qemuio_add_command(const cmdinfo_t *ci)
|
||||
{
|
||||
/* ci->perm assumes a file is open, but the GLOBAL and NOFILE_OK
|
||||
* flags allow it not to be, so that combination is invalid.
|
||||
* Catch it now rather than letting it manifest as a crash if a
|
||||
* particular set of command line options are used.
|
||||
*/
|
||||
assert(ci->perm == 0 ||
|
||||
(ci->flags & (CMD_FLAG_GLOBAL | CMD_NOFILE_OK)) == 0);
|
||||
cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds);
|
||||
cmdtab[ncmds - 1] = *ci;
|
||||
qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
|
||||
@@ -514,7 +521,7 @@ static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
|
||||
}
|
||||
|
||||
co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
bdrv_coroutine_enter(blk_bs(blk), co);
|
||||
while (!data.done) {
|
||||
aio_poll(blk_get_aio_context(blk), true);
|
||||
}
|
||||
|
||||
@@ -999,7 +999,9 @@ static void build_guest_fsinfo_for_virtual_device(char const *syspath,
|
||||
dirpath = g_strdup_printf("%s/slaves", syspath);
|
||||
dir = opendir(dirpath);
|
||||
if (!dir) {
|
||||
error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
|
||||
if (errno != ENOENT) {
|
||||
error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
|
||||
}
|
||||
g_free(dirpath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,6 +207,12 @@ void qmp_cont(Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
blk_resume_after_migration(&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
||||
autostart = 1;
|
||||
} else {
|
||||
|
||||
@@ -195,6 +195,10 @@ void replay_save_instructions(void)
|
||||
if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
|
||||
replay_mutex_lock();
|
||||
int diff = (int)(replay_get_current_step() - replay_state.current_step);
|
||||
|
||||
/* Time can only go forward */
|
||||
assert(diff >= 0);
|
||||
|
||||
if (diff > 0) {
|
||||
replay_put_event(EVENT_INSTRUCTION);
|
||||
replay_put_dword(diff);
|
||||
|
||||
@@ -84,6 +84,10 @@ void replay_account_executed_instructions(void)
|
||||
if (replay_state.instructions_count > 0) {
|
||||
int count = (int)(replay_get_current_step()
|
||||
- replay_state.current_step);
|
||||
|
||||
/* Time can only go forward */
|
||||
assert(count >= 0);
|
||||
|
||||
replay_state.instructions_count -= count;
|
||||
replay_state.current_step += count;
|
||||
if (replay_state.instructions_count == 0) {
|
||||
|
||||
@@ -21,7 +21,15 @@ def isnull(ptr):
|
||||
return ptr == gdb.Value(0).cast(ptr.type)
|
||||
|
||||
def int128(p):
|
||||
return int(p['lo']) + (int(p['hi']) << 64)
|
||||
'''Read an Int128 type to a python integer.
|
||||
|
||||
QEMU can be built with native Int128 support so we need to detect
|
||||
if the value is a structure or the native type.
|
||||
'''
|
||||
if p.type.code == gdb.TYPE_CODE_STRUCT:
|
||||
return int(p['lo']) + (int(p['hi']) << 64)
|
||||
else:
|
||||
return int(("%s" % p), 16)
|
||||
|
||||
class MtreeCommand(gdb.Command):
|
||||
'''Display the memory tree hierarchy'''
|
||||
@@ -69,7 +77,7 @@ class MtreeCommand(gdb.Command):
|
||||
gdb.write('%s alias: %s@%016x (@ %s)\n' %
|
||||
(' ' * level,
|
||||
alias['name'].string(),
|
||||
ptr['alias_offset'],
|
||||
int(ptr['alias_offset']),
|
||||
alias,
|
||||
),
|
||||
gdb.STDOUT)
|
||||
|
||||
+22
-25
@@ -143,17 +143,13 @@ void ndp_send_ra(Slirp *slirp)
|
||||
/* Build IPv6 packet */
|
||||
struct mbuf *t = m_get(slirp);
|
||||
struct ip6 *rip = mtod(t, struct ip6 *);
|
||||
size_t pl_size = 0;
|
||||
struct in6_addr addr;
|
||||
uint32_t scope_id;
|
||||
|
||||
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
|
||||
rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
|
||||
rip->ip_nh = IPPROTO_ICMPV6;
|
||||
rip->ip_pl = htons(ICMP6_NDP_RA_MINLEN
|
||||
+ NDPOPT_LINKLAYER_LEN
|
||||
+ NDPOPT_PREFIXINFO_LEN
|
||||
#ifndef _WIN32
|
||||
+ NDPOPT_RDNSS_LEN
|
||||
#endif
|
||||
);
|
||||
t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
|
||||
|
||||
/* Build ICMPv6 packet */
|
||||
t->m_data += sizeof(struct ip6);
|
||||
@@ -171,6 +167,7 @@ void ndp_send_ra(Slirp *slirp)
|
||||
ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
|
||||
ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
|
||||
t->m_data += ICMP6_NDP_RA_MINLEN;
|
||||
pl_size += ICMP6_NDP_RA_MINLEN;
|
||||
|
||||
/* Source link-layer address (NDP option) */
|
||||
struct ndpopt *opt = mtod(t, struct ndpopt *);
|
||||
@@ -178,6 +175,7 @@ void ndp_send_ra(Slirp *slirp)
|
||||
opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
|
||||
in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
|
||||
t->m_data += NDPOPT_LINKLAYER_LEN;
|
||||
pl_size += NDPOPT_LINKLAYER_LEN;
|
||||
|
||||
/* Prefix information (NDP option) */
|
||||
struct ndpopt *opt2 = mtod(t, struct ndpopt *);
|
||||
@@ -192,27 +190,26 @@ void ndp_send_ra(Slirp *slirp)
|
||||
opt2->ndpopt_prefixinfo.reserved2 = 0;
|
||||
opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
|
||||
t->m_data += NDPOPT_PREFIXINFO_LEN;
|
||||
pl_size += NDPOPT_PREFIXINFO_LEN;
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Prefix information (NDP option) */
|
||||
/* disabled for windows for now, until get_dns6_addr is implemented */
|
||||
struct ndpopt *opt3 = mtod(t, struct ndpopt *);
|
||||
opt3->ndpopt_type = NDPOPT_RDNSS;
|
||||
opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
|
||||
opt3->ndpopt_rdnss.reserved = 0;
|
||||
opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
|
||||
opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
|
||||
t->m_data += NDPOPT_RDNSS_LEN;
|
||||
#endif
|
||||
if (get_dns6_addr(&addr, &scope_id) >= 0) {
|
||||
/* Host system does have an IPv6 DNS server, announce our proxy. */
|
||||
struct ndpopt *opt3 = mtod(t, struct ndpopt *);
|
||||
opt3->ndpopt_type = NDPOPT_RDNSS;
|
||||
opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
|
||||
opt3->ndpopt_rdnss.reserved = 0;
|
||||
opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
|
||||
opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
|
||||
t->m_data += NDPOPT_RDNSS_LEN;
|
||||
pl_size += NDPOPT_RDNSS_LEN;
|
||||
}
|
||||
|
||||
rip->ip_pl = htons(pl_size);
|
||||
t->m_data -= sizeof(struct ip6) + pl_size;
|
||||
t->m_len = sizeof(struct ip6) + pl_size;
|
||||
|
||||
/* ICMPv6 Checksum */
|
||||
#ifndef _WIN32
|
||||
t->m_data -= NDPOPT_RDNSS_LEN;
|
||||
#endif
|
||||
t->m_data -= NDPOPT_PREFIXINFO_LEN;
|
||||
t->m_data -= NDPOPT_LINKLAYER_LEN;
|
||||
t->m_data -= ICMP6_NDP_RA_MINLEN;
|
||||
t->m_data -= sizeof(struct ip6);
|
||||
ricmp->icmp6_cksum = ip6_cksum(t);
|
||||
|
||||
ip6_output(NULL, t, 0);
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
|
||||
const char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
|
||||
if (!res) {
|
||||
res = "(string conversion error)";
|
||||
}
|
||||
|
||||
@@ -391,8 +391,7 @@ int cpu_get_dump_info(ArchDumpInfo *info,
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
X86CPU *first_x86_cpu = X86_CPU(first_cpu);
|
||||
|
||||
lma = !!(first_x86_cpu->env.hflags & HF_LMA_MASK);
|
||||
lma = first_cpu && (first_x86_cpu->env.hflags & HF_LMA_MASK);
|
||||
#endif
|
||||
|
||||
if (lma) {
|
||||
|
||||
+20
-12
@@ -3373,15 +3373,19 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
||||
GList *l;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*TODO: cpu->max_features incorrectly overwrites features
|
||||
* set using "feat=on|off". Once we fix this, we can convert
|
||||
/*TODO: Now cpu->max_features doesn't overwrite features
|
||||
* set using QOM properties, and we can convert
|
||||
* plus_features & minus_features to global properties
|
||||
* inside x86_cpu_parse_featurestr() too.
|
||||
*/
|
||||
if (cpu->max_features) {
|
||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||
env->features[w] =
|
||||
x86_cpu_get_supported_feature_word(w, cpu->migratable);
|
||||
/* Override only features that weren't set explicitly
|
||||
* by the user.
|
||||
*/
|
||||
env->features[w] |=
|
||||
x86_cpu_get_supported_feature_word(w, cpu->migratable) &
|
||||
~env->user_features[w];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3692,15 +3696,17 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
typedef struct BitProperty {
|
||||
uint32_t *ptr;
|
||||
FeatureWord w;
|
||||
uint32_t mask;
|
||||
} BitProperty;
|
||||
|
||||
static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(obj);
|
||||
BitProperty *fp = opaque;
|
||||
bool value = (*fp->ptr & fp->mask) == fp->mask;
|
||||
uint32_t f = cpu->env.features[fp->w];
|
||||
bool value = (f & fp->mask) == fp->mask;
|
||||
visit_type_bool(v, name, &value, errp);
|
||||
}
|
||||
|
||||
@@ -3708,6 +3714,7 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
X86CPU *cpu = X86_CPU(obj);
|
||||
BitProperty *fp = opaque;
|
||||
Error *local_err = NULL;
|
||||
bool value;
|
||||
@@ -3724,10 +3731,11 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name,
|
||||
}
|
||||
|
||||
if (value) {
|
||||
*fp->ptr |= fp->mask;
|
||||
cpu->env.features[fp->w] |= fp->mask;
|
||||
} else {
|
||||
*fp->ptr &= ~fp->mask;
|
||||
cpu->env.features[fp->w] &= ~fp->mask;
|
||||
}
|
||||
cpu->env.user_features[fp->w] |= fp->mask;
|
||||
}
|
||||
|
||||
static void x86_cpu_release_bit_prop(Object *obj, const char *name,
|
||||
@@ -3745,7 +3753,7 @@ static void x86_cpu_release_bit_prop(Object *obj, const char *name,
|
||||
*/
|
||||
static void x86_cpu_register_bit_prop(X86CPU *cpu,
|
||||
const char *prop_name,
|
||||
uint32_t *field,
|
||||
FeatureWord w,
|
||||
int bitnr)
|
||||
{
|
||||
BitProperty *fp;
|
||||
@@ -3755,11 +3763,11 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu,
|
||||
op = object_property_find(OBJECT(cpu), prop_name, NULL);
|
||||
if (op) {
|
||||
fp = op->opaque;
|
||||
assert(fp->ptr == field);
|
||||
assert(fp->w == w);
|
||||
fp->mask |= mask;
|
||||
} else {
|
||||
fp = g_new0(BitProperty, 1);
|
||||
fp->ptr = field;
|
||||
fp->w = w;
|
||||
fp->mask = mask;
|
||||
object_property_add(OBJECT(cpu), prop_name, "bool",
|
||||
x86_cpu_get_bit_prop,
|
||||
@@ -3787,7 +3795,7 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu,
|
||||
/* aliases don't use "|" delimiters anymore, they are registered
|
||||
* manually using object_property_add_alias() */
|
||||
assert(!strchr(name, '|'));
|
||||
x86_cpu_register_bit_prop(cpu, name, &cpu->env.features[w], bitnr);
|
||||
x86_cpu_register_bit_prop(cpu, name, w, bitnr);
|
||||
}
|
||||
|
||||
static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
|
||||
|
||||
@@ -1147,6 +1147,8 @@ typedef struct CPUX86State {
|
||||
uint32_t cpuid_vendor3;
|
||||
uint32_t cpuid_version;
|
||||
FeatureWordArray features;
|
||||
/* Features that were explicitly enabled/disabled */
|
||||
FeatureWordArray user_features;
|
||||
uint32_t cpuid_model[12];
|
||||
|
||||
/* MTRRs */
|
||||
|
||||
@@ -326,6 +326,10 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f,
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
APICCommonState *s = APIC_COMMON(cpu->apic_state);
|
||||
if (!s) {
|
||||
cpu_fprintf(f, "local apic state not available\n");
|
||||
return;
|
||||
}
|
||||
uint32_t *lvt = s->lvt;
|
||||
|
||||
cpu_fprintf(f, "dumping local APIC state for CPU %-2u\n\n",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
@@ -156,7 +157,9 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
|
||||
break;
|
||||
case 8:
|
||||
if (!(env->hflags2 & HF2_VINTR_MASK)) {
|
||||
qemu_mutex_lock_iothread();
|
||||
cpu_set_apic_tpr(x86_env_get_cpu(env)->apic_state, t0);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
env->v_tpr = t0 & 0x0f;
|
||||
break;
|
||||
|
||||
@@ -843,6 +843,29 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
|
||||
static tcg_insn_unit *qemu_ld_trampoline[16];
|
||||
static tcg_insn_unit *qemu_st_trampoline[16];
|
||||
|
||||
static void emit_extend(TCGContext *s, TCGReg r, int op)
|
||||
{
|
||||
/* Emit zero extend of 8, 16 or 32 bit data as
|
||||
* required by the MO_* value op; do nothing for 64 bit.
|
||||
*/
|
||||
switch (op & MO_SIZE) {
|
||||
case MO_8:
|
||||
tcg_out_arithi(s, r, r, 0xff, ARITH_AND);
|
||||
break;
|
||||
case MO_16:
|
||||
tcg_out_arithi(s, r, r, 16, SHIFT_SLL);
|
||||
tcg_out_arithi(s, r, r, 16, SHIFT_SRL);
|
||||
break;
|
||||
case MO_32:
|
||||
if (SPARC64) {
|
||||
tcg_out_arith(s, r, r, 0, SHIFT_SRL);
|
||||
}
|
||||
break;
|
||||
case MO_64:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void build_trampolines(TCGContext *s)
|
||||
{
|
||||
static void * const qemu_ld_helpers[16] = {
|
||||
@@ -910,6 +933,7 @@ static void build_trampolines(TCGContext *s)
|
||||
qemu_st_trampoline[i] = s->code_ptr;
|
||||
|
||||
if (SPARC64) {
|
||||
emit_extend(s, TCG_REG_O2, i);
|
||||
ra = TCG_REG_O4;
|
||||
} else {
|
||||
ra = TCG_REG_O1;
|
||||
@@ -925,6 +949,7 @@ static void build_trampolines(TCGContext *s)
|
||||
tcg_out_arithi(s, ra, ra + 1, 32, SHIFT_SRLX);
|
||||
ra += 2;
|
||||
} else {
|
||||
emit_extend(s, ra, i);
|
||||
ra += 1;
|
||||
}
|
||||
/* Skip the oi argument. */
|
||||
@@ -1119,7 +1144,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
|
||||
/* Skip the high-part; we'll perform the extract in the trampoline. */
|
||||
param++;
|
||||
}
|
||||
tcg_out_mov(s, TCG_TYPE_REG, param++, addr);
|
||||
tcg_out_mov(s, TCG_TYPE_REG, param++, addrz);
|
||||
|
||||
/* We use the helpers to extend SB and SW data, leaving the case
|
||||
of SL needing explicit extending below. */
|
||||
@@ -1199,7 +1224,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr,
|
||||
/* Skip the high-part; we'll perform the extract in the trampoline. */
|
||||
param++;
|
||||
}
|
||||
tcg_out_mov(s, TCG_TYPE_REG, param++, addr);
|
||||
tcg_out_mov(s, TCG_TYPE_REG, param++, addrz);
|
||||
if (!SPARC64 && (memop & MO_SIZE) == MO_64) {
|
||||
/* Skip the high-part; we'll perform the extract in the trampoline. */
|
||||
param++;
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ typedef struct {
|
||||
gsize asl_len;
|
||||
gchar *asl_file;
|
||||
bool tmp_files_retain; /* do not delete the temp asl/aml */
|
||||
} QEMU_PACKED AcpiSdtTable;
|
||||
} AcpiSdtTable;
|
||||
|
||||
#define ACPI_READ_FIELD(field, addr) \
|
||||
do { \
|
||||
|
||||
@@ -167,6 +167,14 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
|
||||
socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
|
||||
qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
|
||||
|
||||
/* It's possible that if an earlier test run crashed it might
|
||||
* have left a stale unix socket lying around. Delete any
|
||||
* stale old socket to avoid spurious test failures with
|
||||
* tests/libqtest.c:70:init_socket: assertion failed (ret != -1): (-1 != -1)
|
||||
*/
|
||||
unlink(socket_path);
|
||||
unlink(qmp_socket_path);
|
||||
|
||||
sock = init_socket(socket_path);
|
||||
qmpsock = init_socket(qmp_socket_path);
|
||||
|
||||
|
||||
@@ -966,5 +966,51 @@ class TestRepairQuorum(iotests.QMPTestCase):
|
||||
# to check that this file is really driven by quorum
|
||||
self.vm.shutdown()
|
||||
|
||||
# Test mirroring with a source that does not have any parents (not even a
|
||||
# BlockBackend)
|
||||
class TestOrphanedSource(iotests.QMPTestCase):
|
||||
def setUp(self):
|
||||
blk0 = { 'node-name': 'src',
|
||||
'driver': 'null-co' }
|
||||
|
||||
blk1 = { 'node-name': 'dest',
|
||||
'driver': 'null-co' }
|
||||
|
||||
blk2 = { 'node-name': 'dest-ro',
|
||||
'driver': 'null-co',
|
||||
'read-only': 'on' }
|
||||
|
||||
self.vm = iotests.VM()
|
||||
self.vm.add_blockdev(self.qmp_to_opts(blk0))
|
||||
self.vm.add_blockdev(self.qmp_to_opts(blk1))
|
||||
self.vm.add_blockdev(self.qmp_to_opts(blk2))
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
|
||||
def test_no_job_id(self):
|
||||
self.assert_no_active_block_jobs()
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror', device='src', sync='full',
|
||||
target='dest')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
def test_success(self):
|
||||
self.assert_no_active_block_jobs()
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror', job_id='job', device='src',
|
||||
sync='full', target='dest')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.complete_and_wait('job')
|
||||
|
||||
def test_failing_permissions(self):
|
||||
self.assert_no_active_block_jobs()
|
||||
|
||||
result = self.vm.qmp('blockdev-mirror', device='src', sync='full',
|
||||
target='dest-ro')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
|
||||
if __name__ == '__main__':
|
||||
iotests.main(supported_fmts=['qcow2', 'qed'])
|
||||
@@ -1,5 +1,5 @@
|
||||
............................................................................
|
||||
...............................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 76 tests
|
||||
Ran 79 tests
|
||||
|
||||
OK
|
||||
+12
-15
@@ -56,30 +56,25 @@ _supported_os Linux
|
||||
# 3: Two-layer backing chain, commit to lower backing file
|
||||
# (in this case, the top image will implicitly stay unchanged)
|
||||
#
|
||||
# Each pass is run twice, since qcow2 has different code paths for cleaning
|
||||
# an image depending on whether it has a snapshot.
|
||||
#
|
||||
# 020 already tests committing, so this only tests whether image chains are
|
||||
# working properly and that all images above the base are emptied; therefore,
|
||||
# no complicated patterns are necessary. Check near the 2G mark, as qcow2
|
||||
# has been buggy at that boundary in the past.
|
||||
for i in 0 1 2 3; do
|
||||
for j in 0 1; do
|
||||
|
||||
echo
|
||||
echo "=== Test pass $i.$j ==="
|
||||
echo "=== Test pass $i ==="
|
||||
echo
|
||||
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img 2100M
|
||||
TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" 2100M
|
||||
_make_test_img -b "$TEST_IMG.itmd" 2100M
|
||||
if [ $j -eq 0 ]; then
|
||||
$QEMU_IMG snapshot -c snap "$TEST_IMG"
|
||||
fi
|
||||
len=$((2100 * 1024 * 1024 + 512)) # larger than 2G, and not cluster aligned
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img $len
|
||||
TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" $len
|
||||
_make_test_img -b "$TEST_IMG.itmd" $len
|
||||
|
||||
$QEMU_IO -c 'write -P 1 0x7ffd0000 192k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c 'write -P 2 0x7ffe0000 128k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c 'write -P 3 0x7fff0000 64k' "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 1 0x7ffd0000 192k" "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 2 0x7ffe0000 128k" "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 3 0x7fff0000 64k" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 4 $(($len - 512)) 512" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
if [ $i -lt 3 ]; then
|
||||
if [ $i == 0 ]; then
|
||||
@@ -97,11 +92,13 @@ if [ $i -lt 3 ]; then
|
||||
|
||||
# Bottom should be unchanged
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 192k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 0 $((len - 512)) 512" "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
# Intermediate should contain changes from top
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 2 0x7ffe0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 3 0x7fff0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 4 $((len - 512)) 512" "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
|
||||
# And in pass 0, the top image should be empty, whereas in both other passes
|
||||
# it should be unchanged (which is both checked by qemu-img map)
|
||||
@@ -112,6 +109,7 @@ else
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 2 0x7ffe0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 3 0x7fff0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 4 $((len - 512)) 512" "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
# Both top and intermediate should be unchanged
|
||||
fi
|
||||
@@ -121,7 +119,6 @@ $QEMU_IMG map "$TEST_IMG.itmd" | _filter_qemu_img_map
|
||||
$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
# success, all done
|
||||
|
||||
+47
-133
@@ -1,222 +1,131 @@
|
||||
QA output created by 097
|
||||
|
||||
=== Test pass 0.0 ===
|
||||
=== Test pass 0 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
|
||||
=== Test pass 0.1 ===
|
||||
=== Test pass 1 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
|
||||
=== Test pass 1.0 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 1.1 ===
|
||||
=== Test pass 2 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 2.0 ===
|
||||
=== Test pass 3 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 2.1 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 3.0 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 3.1 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202009600
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202009600 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -224,13 +133,18 @@ read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
*** done
|
||||
@@ -10,7 +10,7 @@ Automatically detecting the format is dangerous for raw images, write operations
|
||||
Specify the 'raw' format explicitly to remove the restrictions.
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"return": []}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -73,7 +73,7 @@ Automatically detecting the format is dangerous for raw images, write operations
|
||||
Specify the 'raw' format explicitly to remove the restrictions.
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"return": []}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -115,7 +115,7 @@ Automatically detecting the format is dangerous for raw images, write operations
|
||||
Specify the 'raw' format explicitly to remove the restrictions.
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"return": []}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -135,7 +135,7 @@ Automatically detecting the format is dangerous for raw images, write operations
|
||||
Specify the 'raw' format explicitly to remove the restrictions.
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"return": []}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -195,7 +195,7 @@ Automatically detecting the format is dangerous for raw images, write operations
|
||||
Specify the 'raw' format explicitly to remove the restrictions.
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
|
||||
{"return": []}
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
+17
-8
@@ -30,6 +30,13 @@ NBD_PORT = 10811
|
||||
test_img = os.path.join(iotests.test_dir, 'test.img')
|
||||
unix_socket = os.path.join(iotests.test_dir, 'nbd.socket')
|
||||
|
||||
|
||||
def flatten_sock_addr(crumpled_address):
|
||||
result = { 'type': crumpled_address['type'] }
|
||||
result.update(crumpled_address['data'])
|
||||
return result
|
||||
|
||||
|
||||
class NBDBlockdevAddBase(iotests.QMPTestCase):
|
||||
def blockdev_add_options(self, address, export=None):
|
||||
options = { 'node-name': 'nbd-blockdev',
|
||||
@@ -85,13 +92,15 @@ class QemuNBD(NBDBlockdevAddBase):
|
||||
'host': 'localhost',
|
||||
'port': str(NBD_PORT)
|
||||
} }
|
||||
self.client_test('nbd://localhost:%i' % NBD_PORT, address)
|
||||
self.client_test('nbd://localhost:%i' % NBD_PORT,
|
||||
flatten_sock_addr(address))
|
||||
|
||||
def test_unix(self):
|
||||
self._server_up('-k', unix_socket)
|
||||
address = { 'type': 'unix',
|
||||
'data': { 'path': unix_socket } }
|
||||
self.client_test('nbd+unix://?socket=' + unix_socket, address)
|
||||
self.client_test('nbd+unix://?socket=' + unix_socket,
|
||||
flatten_sock_addr(address))
|
||||
|
||||
|
||||
class BuiltinNBD(NBDBlockdevAddBase):
|
||||
@@ -134,7 +143,7 @@ class BuiltinNBD(NBDBlockdevAddBase):
|
||||
} }
|
||||
self._server_up(address)
|
||||
self.client_test('nbd://localhost:%i/nbd-export' % NBD_PORT,
|
||||
address, 'nbd-export')
|
||||
flatten_sock_addr(address), 'nbd-export')
|
||||
self._server_down()
|
||||
|
||||
def test_inet6(self):
|
||||
@@ -149,10 +158,10 @@ class BuiltinNBD(NBDBlockdevAddBase):
|
||||
'file': {
|
||||
'driver': 'nbd',
|
||||
'export': 'nbd-export',
|
||||
'server': address
|
||||
'server': flatten_sock_addr(address)
|
||||
} }
|
||||
self._server_up(address)
|
||||
self.client_test(filename, address, 'nbd-export')
|
||||
self.client_test(filename, flatten_sock_addr(address), 'nbd-export')
|
||||
self._server_down()
|
||||
|
||||
def test_unix(self):
|
||||
@@ -160,7 +169,7 @@ class BuiltinNBD(NBDBlockdevAddBase):
|
||||
'data': { 'path': unix_socket } }
|
||||
self._server_up(address)
|
||||
self.client_test('nbd+unix:///nbd-export?socket=' + unix_socket,
|
||||
address, 'nbd-export')
|
||||
flatten_sock_addr(address), 'nbd-export')
|
||||
self._server_down()
|
||||
|
||||
def test_fd(self):
|
||||
@@ -182,9 +191,9 @@ class BuiltinNBD(NBDBlockdevAddBase):
|
||||
'file': {
|
||||
'driver': 'nbd',
|
||||
'export': 'nbd-export',
|
||||
'server': address
|
||||
'server': flatten_sock_addr(address)
|
||||
} }
|
||||
self.client_test(filename, address, 'nbd-export')
|
||||
self.client_test(filename, flatten_sock_addr(address), 'nbd-export')
|
||||
|
||||
self._server_down()
|
||||
|
||||
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Commit changes into backing chains and empty the top image if the
|
||||
# backing image is not explicitly specified.
|
||||
#
|
||||
# Variant of 097, which includes snapshots to test different codepath
|
||||
# in qcow2
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
_rm_test_img "$TEST_IMG.itmd"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.pattern
|
||||
|
||||
# Any format supporting backing files and bdrv_make_empty
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
# Four passes:
|
||||
# 0: Two-layer backing chain, commit to upper backing file (implicitly)
|
||||
# (in this case, the top image will be emptied)
|
||||
# 1: Two-layer backing chain, commit to upper backing file (explicitly)
|
||||
# (in this case, the top image will implicitly stay unchanged)
|
||||
# 2: Two-layer backing chain, commit to upper backing file (implicitly with -d)
|
||||
# (in this case, the top image will explicitly stay unchanged)
|
||||
# 3: Two-layer backing chain, commit to lower backing file
|
||||
# (in this case, the top image will implicitly stay unchanged)
|
||||
#
|
||||
# 020 already tests committing, so this only tests whether image chains are
|
||||
# working properly and that all images above the base are emptied; therefore,
|
||||
# no complicated patterns are necessary. Check near the 2G mark, as qcow2
|
||||
# has been buggy at that boundary in the past.
|
||||
for i in 0 1 2 3; do
|
||||
|
||||
echo
|
||||
echo "=== Test pass $i ==="
|
||||
echo
|
||||
|
||||
len=$((2100 * 1024 * 1024 + 512)) # larger than 2G, and not cluster aligned
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img $len
|
||||
TEST_IMG="$TEST_IMG.itmd" _make_test_img -b "$TEST_IMG.base" $len
|
||||
_make_test_img -b "$TEST_IMG.itmd" $len
|
||||
$QEMU_IMG snapshot -c snap "$TEST_IMG"
|
||||
|
||||
$QEMU_IO -c "write -P 1 0x7ffd0000 192k" "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 2 0x7ffe0000 128k" "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 3 0x7fff0000 64k" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c "write -P 4 $(($len - 512)) 512" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
if [ $i -lt 3 ]; then
|
||||
if [ $i == 0 ]; then
|
||||
# -b "$TEST_IMG.itmd" should be the default (that is, committing to the
|
||||
# first backing file in the chain)
|
||||
$QEMU_IMG commit "$TEST_IMG"
|
||||
elif [ $i == 1 ]; then
|
||||
# explicitly specify the commit target (this should imply -d)
|
||||
$QEMU_IMG commit -b "$TEST_IMG.itmd" "$TEST_IMG"
|
||||
else
|
||||
# do not explicitly specify the commit target, but use -d to leave the
|
||||
# top image unchanged
|
||||
$QEMU_IMG commit -d "$TEST_IMG"
|
||||
fi
|
||||
|
||||
# Bottom should be unchanged
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 192k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 0 $((len - 512)) 512" "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
# Intermediate should contain changes from top
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 2 0x7ffe0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 3 0x7fff0000 64k' "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 4 $((len - 512)) 512" "$TEST_IMG.itmd" | _filter_qemu_io
|
||||
|
||||
# And in pass 0, the top image should be empty, whereas in both other passes
|
||||
# it should be unchanged (which is both checked by qemu-img map)
|
||||
else
|
||||
$QEMU_IMG commit -b "$TEST_IMG.base" "$TEST_IMG"
|
||||
|
||||
# Bottom should contain all changes
|
||||
$QEMU_IO -c 'read -P 1 0x7ffd0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 2 0x7ffe0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c 'read -P 3 0x7fff0000 64k' "$TEST_IMG.base" | _filter_qemu_io
|
||||
$QEMU_IO -c "read -P 4 $((len - 512)) 512" "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
# Both top and intermediate should be unchanged
|
||||
fi
|
||||
|
||||
$QEMU_IMG map "$TEST_IMG.base" | _filter_qemu_img_map
|
||||
$QEMU_IMG map "$TEST_IMG.itmd" | _filter_qemu_img_map
|
||||
$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map
|
||||
|
||||
done
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
@@ -0,0 +1,150 @@
|
||||
QA output created by 176
|
||||
|
||||
=== Test pass 0 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
|
||||
=== Test pass 1 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 2 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
|
||||
=== Test pass 3 ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=2202010112
|
||||
Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.base
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2202010112 backing_file=TEST_DIR/t.IMGFMT.itmd
|
||||
wrote 196608/196608 bytes at offset 2147287040
|
||||
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 2147352576
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
read 65536/65536 bytes at offset 2147287040
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147352576
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 2147418112
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 2202009600
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Offset Length File
|
||||
0x7ffd0000 0x30000 TEST_DIR/t.IMGFMT.base
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT.base
|
||||
Offset Length File
|
||||
0x7ffd0000 0x10000 TEST_DIR/t.IMGFMT.base
|
||||
0x7ffe0000 0x10000 TEST_DIR/t.IMGFMT.itmd
|
||||
0x7fff0000 0x10000 TEST_DIR/t.IMGFMT
|
||||
0x83400000 0x200 TEST_DIR/t.IMGFMT
|
||||
*** done
|
||||
@@ -168,3 +168,4 @@
|
||||
173 rw auto
|
||||
174 auto
|
||||
175 auto quick
|
||||
176 rw auto backing
|
||||
@@ -177,6 +177,14 @@ class VM(qtest.QEMUQtestMachine):
|
||||
self._num_drives += 1
|
||||
return self
|
||||
|
||||
def add_blockdev(self, opts):
|
||||
self._args.append('-blockdev')
|
||||
if isinstance(opts, str):
|
||||
self._args.append(opts)
|
||||
else:
|
||||
self._args.append(','.join(opts))
|
||||
return self
|
||||
|
||||
def pause_drive(self, drive, event=None):
|
||||
'''Pause drive r/w operations'''
|
||||
if not event:
|
||||
@@ -235,6 +243,13 @@ class QMPTestCase(unittest.TestCase):
|
||||
output[basestr[:-1]] = obj # Strip trailing '.'
|
||||
return output
|
||||
|
||||
def qmp_to_opts(self, obj):
|
||||
obj = self.flatten_qmp_object(obj)
|
||||
output_list = list()
|
||||
for key in obj:
|
||||
output_list += [key + '=' + obj[key]]
|
||||
return ','.join(output_list)
|
||||
|
||||
def assert_qmp_absent(self, d, path):
|
||||
try:
|
||||
result = self.dictpath(d, path)
|
||||
|
||||
@@ -110,7 +110,6 @@ static BlockJob *test_block_job_start(unsigned int iterations,
|
||||
s->result = result;
|
||||
data->job = s;
|
||||
data->result = result;
|
||||
block_job_start(&s->common);
|
||||
return &s->common;
|
||||
}
|
||||
|
||||
@@ -123,6 +122,7 @@ static void test_single_job(int expected)
|
||||
txn = block_job_txn_new();
|
||||
job = test_block_job_start(1, true, expected, &result);
|
||||
block_job_txn_add_job(txn, job);
|
||||
block_job_start(job);
|
||||
|
||||
if (expected == -ECANCELED) {
|
||||
block_job_cancel(job);
|
||||
@@ -164,6 +164,8 @@ static void test_pair_jobs(int expected1, int expected2)
|
||||
block_job_txn_add_job(txn, job1);
|
||||
job2 = test_block_job_start(2, true, expected2, &result2);
|
||||
block_job_txn_add_job(txn, job2);
|
||||
block_job_start(job1);
|
||||
block_job_start(job2);
|
||||
|
||||
if (expected1 == -ECANCELED) {
|
||||
block_job_cancel(job1);
|
||||
@@ -223,6 +225,8 @@ static void test_pair_jobs_fail_cancel_race(void)
|
||||
block_job_txn_add_job(txn, job1);
|
||||
job2 = test_block_job_start(2, false, 0, &result2);
|
||||
block_job_txn_add_job(txn, job2);
|
||||
block_job_start(job1);
|
||||
block_job_start(job2);
|
||||
|
||||
block_job_cancel(job1);
|
||||
|
||||
|
||||
@@ -234,6 +234,8 @@ static void test_io_channel(bool async,
|
||||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(!passFD ||
|
||||
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
|
||||
test = qio_channel_test_new();
|
||||
qio_channel_test_run_threads(test, true, src, dst);
|
||||
@@ -248,6 +250,8 @@ static void test_io_channel(bool async,
|
||||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(!passFD ||
|
||||
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
|
||||
test = qio_channel_test_new();
|
||||
qio_channel_test_run_threads(test, false, src, dst);
|
||||
@@ -262,6 +266,8 @@ static void test_io_channel(bool async,
|
||||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(!passFD ||
|
||||
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
|
||||
test = qio_channel_test_new();
|
||||
qio_channel_test_run_threads(test, true, src, dst);
|
||||
@@ -276,6 +282,8 @@ static void test_io_channel(bool async,
|
||||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(!passFD ||
|
||||
qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS));
|
||||
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
|
||||
|
||||
test = qio_channel_test_new();
|
||||
qio_channel_test_run_threads(test, false, src, dst);
|
||||
|
||||
+12
-5
@@ -169,6 +169,8 @@ struct InputLinux {
|
||||
bool has_abs_x;
|
||||
int num_keys;
|
||||
int num_btns;
|
||||
struct input_event event;
|
||||
int read_offset;
|
||||
|
||||
QTAILQ_ENTRY(InputLinux) next;
|
||||
};
|
||||
@@ -327,25 +329,30 @@ static void input_linux_handle_mouse(InputLinux *il, struct input_event *event)
|
||||
static void input_linux_event(void *opaque)
|
||||
{
|
||||
InputLinux *il = opaque;
|
||||
struct input_event event;
|
||||
int rc;
|
||||
int read_size;
|
||||
uint8_t *p = (uint8_t *)&il->event;
|
||||
|
||||
for (;;) {
|
||||
rc = read(il->fd, &event, sizeof(event));
|
||||
if (rc != sizeof(event)) {
|
||||
read_size = sizeof(il->event) - il->read_offset;
|
||||
rc = read(il->fd, &p[il->read_offset], read_size);
|
||||
if (rc != read_size) {
|
||||
if (rc < 0 && errno != EAGAIN) {
|
||||
fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno));
|
||||
qemu_set_fd_handler(il->fd, NULL, NULL, NULL);
|
||||
close(il->fd);
|
||||
} else if (rc > 0) {
|
||||
il->read_offset += rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
il->read_offset = 0;
|
||||
|
||||
if (il->num_keys) {
|
||||
input_linux_handle_keyboard(il, &event);
|
||||
input_linux_handle_keyboard(il, &il->event);
|
||||
}
|
||||
if (il->has_rel_x && il->num_btns) {
|
||||
input_linux_handle_mouse(il, &event);
|
||||
input_linux_handle_mouse(il, &il->event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,10 +129,13 @@ static void vnc_init_basic_info(SocketAddress *addr,
|
||||
info->family = NETWORK_ADDRESS_FAMILY_UNIX;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported socket kind %d",
|
||||
addr->type);
|
||||
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
error_setg(errp, "Unsupported socket address type %s",
|
||||
SocketAddressKind_lookup[addr->type]);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -411,10 +414,13 @@ VncInfo *qmp_query_vnc(Error **errp)
|
||||
info->family = NETWORK_ADDRESS_FAMILY_UNIX;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported socket kind %d",
|
||||
addr->type);
|
||||
case SOCKET_ADDRESS_KIND_VSOCK:
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
error_setg(errp, "Unsupported socket address type %s",
|
||||
SocketAddressKind_lookup[addr->type]);
|
||||
goto out_error;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
info->has_host = true;
|
||||
@@ -3642,6 +3648,7 @@ static int vnc_display_connect(VncDisplay *vd,
|
||||
error_setg(errp, "Expected a single address in reverse mode");
|
||||
return -1;
|
||||
}
|
||||
/* TODO SOCKET_ADDRESS_KIND_FD when fd has AF_UNIX */
|
||||
vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_KIND_UNIX;
|
||||
sioc = qio_channel_socket_new();
|
||||
qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
|
||||
@@ -3786,10 +3793,6 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (saddr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
password = qemu_opt_get_bool(opts, "password", false);
|
||||
if (password) {
|
||||
if (fips_get_state()) {
|
||||
@@ -3974,6 +3977,10 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
register_displaychangelistener(&vd->dcl);
|
||||
}
|
||||
|
||||
if (saddr == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
if (vnc_display_connect(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) {
|
||||
goto fail;
|
||||
|
||||
+6
-1
@@ -453,6 +453,11 @@ void aio_co_wake(struct Coroutine *co)
|
||||
smp_read_barrier_depends();
|
||||
ctx = atomic_read(&co->ctx);
|
||||
|
||||
aio_co_enter(ctx, co);
|
||||
}
|
||||
|
||||
void aio_co_enter(AioContext *ctx, struct Coroutine *co)
|
||||
{
|
||||
if (ctx != qemu_get_current_aio_context()) {
|
||||
aio_co_schedule(ctx, co);
|
||||
return;
|
||||
@@ -464,7 +469,7 @@ void aio_co_wake(struct Coroutine *co)
|
||||
QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, co, co_queue_next);
|
||||
} else {
|
||||
aio_context_acquire(ctx);
|
||||
qemu_coroutine_enter(co);
|
||||
qemu_aio_coroutine_enter(ctx, co);
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,10 @@ void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
if (e->rfd != e->wfd) {
|
||||
close(e->rfd);
|
||||
e->rfd = -1;
|
||||
}
|
||||
close(e->wfd);
|
||||
e->wfd = -1;
|
||||
}
|
||||
|
||||
int event_notifier_get_fd(const EventNotifier *e)
|
||||
|
||||
@@ -25,6 +25,7 @@ int event_notifier_init(EventNotifier *e, int active)
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
CloseHandle(e->event);
|
||||
e->event = NULL;
|
||||
}
|
||||
|
||||
HANDLE event_notifier_get_handle(EventNotifier *e)
|
||||
|
||||
@@ -218,9 +218,12 @@ static void glib_pollfds_poll(void)
|
||||
|
||||
static int os_host_main_loop_wait(int64_t timeout)
|
||||
{
|
||||
GMainContext *context = g_main_context_default();
|
||||
int ret;
|
||||
static int spin_counter;
|
||||
|
||||
g_main_context_acquire(context);
|
||||
|
||||
glib_pollfds_fill(&timeout);
|
||||
|
||||
/* If the I/O thread is very busy or we are incorrectly busy waiting in
|
||||
@@ -256,6 +259,9 @@ static int os_host_main_loop_wait(int64_t timeout)
|
||||
}
|
||||
|
||||
glib_pollfds_poll();
|
||||
|
||||
g_main_context_release(context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
@@ -412,12 +418,15 @@ static int os_host_main_loop_wait(int64_t timeout)
|
||||
fd_set rfds, wfds, xfds;
|
||||
int nfds;
|
||||
|
||||
g_main_context_acquire(context);
|
||||
|
||||
/* XXX: need to suppress polling by better using win32 events */
|
||||
ret = 0;
|
||||
for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
|
||||
ret |= pe->func(pe->opaque);
|
||||
}
|
||||
if (ret != 0) {
|
||||
g_main_context_release(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -472,6 +481,8 @@ static int os_host_main_loop_wait(int64_t timeout)
|
||||
g_main_context_dispatch(context);
|
||||
}
|
||||
|
||||
g_main_context_release(context);
|
||||
|
||||
return select_ret || g_poll_ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -102,12 +102,12 @@ static void coroutine_delete(Coroutine *co)
|
||||
qemu_coroutine_delete(co);
|
||||
}
|
||||
|
||||
void qemu_coroutine_enter(Coroutine *co)
|
||||
void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co)
|
||||
{
|
||||
Coroutine *self = qemu_coroutine_self();
|
||||
CoroutineAction ret;
|
||||
|
||||
trace_qemu_coroutine_enter(self, co, co->entry_arg);
|
||||
trace_qemu_aio_coroutine_enter(ctx, self, co, co->entry_arg);
|
||||
|
||||
if (co->caller) {
|
||||
fprintf(stderr, "Co-routine re-entered recursively\n");
|
||||
@@ -115,7 +115,7 @@ void qemu_coroutine_enter(Coroutine *co)
|
||||
}
|
||||
|
||||
co->caller = self;
|
||||
co->ctx = qemu_get_current_aio_context();
|
||||
co->ctx = ctx;
|
||||
|
||||
/* Store co->ctx before anything that stores co. Matches
|
||||
* barrier in aio_co_wake and qemu_co_mutex_wake.
|
||||
@@ -139,6 +139,11 @@ void qemu_coroutine_enter(Coroutine *co)
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_coroutine_enter(Coroutine *co)
|
||||
{
|
||||
qemu_aio_coroutine_enter(qemu_get_current_aio_context(), co);
|
||||
}
|
||||
|
||||
void qemu_coroutine_enter_if_inactive(Coroutine *co)
|
||||
{
|
||||
if (!qemu_coroutine_entered(co)) {
|
||||
|
||||
+37
-3
@@ -25,6 +25,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
@@ -1154,6 +1155,10 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* TODO SOCKET_ADDRESS_KIND_FD when fd is AF_INET or AF_INET6
|
||||
* (although other address families can do SOCK_DGRAM, too)
|
||||
*/
|
||||
switch (remote->type) {
|
||||
case SOCKET_ADDRESS_KIND_INET:
|
||||
fd = inet_dgram_saddr(remote->u.inet.data,
|
||||
@@ -1333,9 +1338,38 @@ char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "socket family %d unsupported",
|
||||
addr->type);
|
||||
return NULL;
|
||||
abort();
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
SocketAddress *socket_address_crumple(SocketAddressFlat *addr_flat)
|
||||
{
|
||||
SocketAddress *addr = g_new(SocketAddress, 1);
|
||||
|
||||
switch (addr_flat->type) {
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_INET:
|
||||
addr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
addr->u.inet.data = QAPI_CLONE(InetSocketAddress,
|
||||
&addr_flat->u.inet);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_UNIX:
|
||||
addr->type = SOCKET_ADDRESS_KIND_UNIX;
|
||||
addr->u.q_unix.data = QAPI_CLONE(UnixSocketAddress,
|
||||
&addr_flat->u.q_unix);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_VSOCK:
|
||||
addr->type = SOCKET_ADDRESS_KIND_VSOCK;
|
||||
addr->u.vsock.data = QAPI_CLONE(VsockSocketAddress,
|
||||
&addr_flat->u.vsock);
|
||||
break;
|
||||
case SOCKET_ADDRESS_FLAT_TYPE_FD:
|
||||
addr->type = SOCKET_ADDRESS_KIND_FD;
|
||||
addr->u.fd.data = QAPI_CLONE(String, &addr_flat->u.fd);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
+1
-1
@@ -22,7 +22,7 @@ buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from %
|
||||
buffer_free(const char *buf, size_t len) "%s: capacity %zd"
|
||||
|
||||
# util/qemu-coroutine.c
|
||||
qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p"
|
||||
qemu_aio_coroutine_enter(void *ctx, void *from, void *to, void *opaque) "ctx %p from %p to %p opaque %p"
|
||||
qemu_coroutine_yield(void *from, void *to) "from %p to %p"
|
||||
qemu_coroutine_terminate(void *co) "self %p"
|
||||
|
||||
|
||||
Reference in new issue
Block a user