mirror of https://github.com/xemu-project/xemu.git
nbd patches for 2021-02-12
- let qemu-nbd handle larger backlog of connecting clients - fix a few NBD-related iotest failures - add block cancellation hook for faster response to NBD failures -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAmAm3cQACgkQp6FrSiUn Q2rjIggAmDt3oPxm0lvaMWH8NeQ2FO/sVxWbIbXzJfLn189Fyq3tQdM4x3fO64kZ 7tCFqPwgfU3S8opYou+Rs+IhzktJ8VuMUasl1g//YVjyTQkUt2Ppx6cAVAqnvE36 1+5G3On43afFkEcC+oQSeoGuecSMaTdSbjNBu3IGUoK0US3QDO0j4/ywGkVLxw8z 39GeeQgDrViL8OH5MtczuGPvxeCYsqYAe6zrlKsh+ke8/2Q2WUAOfPZpvfSNJ+Qp pXHcwNlZZEVVIpmwmc3jYCfQvGkw//cS8tpZzDx7fB746q1VWGtcWF28SvZfW+PN PxrYF/1IO+ho/tX7fsIJE2fbd9QwPQ== =bDgk -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-02-12' into staging nbd patches for 2021-02-12 - let qemu-nbd handle larger backlog of connecting clients - fix a few NBD-related iotest failures - add block cancellation hook for faster response to NBD failures # gpg: Signature made Fri 12 Feb 2021 19:57:56 GMT # gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full] # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full] # gpg: aka "[jpeg image of size 6874]" [full] # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-nbd-2021-02-12: iotests/264: add backup-cancel test-case block/backup: implement .cancel job handler iotests/264: add mirror-cancel test-case iotests.py: qemu_nbd_popen: remove pid file after use iotests/264: move to python unittest block/mirror: implement .cancel job handler job: add .cancel handler for the driver block/raw-format: implement .bdrv_cancel_in_flight handler block/nbd: implement .bdrv_cancel_in_flight block: add new BlockDriver handler: bdrv_cancel_in_flight io: error_prepend() in qio_channel_readv_full_all() causes segfault iotests/210: Fix reference output qemu-nbd: Permit --shared=0 for unlimited clients qemu-nbd: Use SOMAXCONN for socket listen() backlog Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
abb8b29aff
|
@ -35,6 +35,7 @@ typedef struct BackupBlockJob {
|
||||||
BlockJob common;
|
BlockJob common;
|
||||||
BlockDriverState *backup_top;
|
BlockDriverState *backup_top;
|
||||||
BlockDriverState *source_bs;
|
BlockDriverState *source_bs;
|
||||||
|
BlockDriverState *target_bs;
|
||||||
|
|
||||||
BdrvDirtyBitmap *sync_bitmap;
|
BdrvDirtyBitmap *sync_bitmap;
|
||||||
|
|
||||||
|
@ -329,6 +330,13 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void backup_cancel(Job *job)
|
||||||
|
{
|
||||||
|
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||||
|
|
||||||
|
bdrv_cancel_in_flight(s->target_bs);
|
||||||
|
}
|
||||||
|
|
||||||
static const BlockJobDriver backup_job_driver = {
|
static const BlockJobDriver backup_job_driver = {
|
||||||
.job_driver = {
|
.job_driver = {
|
||||||
.instance_size = sizeof(BackupBlockJob),
|
.instance_size = sizeof(BackupBlockJob),
|
||||||
|
@ -340,6 +348,7 @@ static const BlockJobDriver backup_job_driver = {
|
||||||
.abort = backup_abort,
|
.abort = backup_abort,
|
||||||
.clean = backup_clean,
|
.clean = backup_clean,
|
||||||
.pause = backup_pause,
|
.pause = backup_pause,
|
||||||
|
.cancel = backup_cancel,
|
||||||
},
|
},
|
||||||
.set_speed = backup_set_speed,
|
.set_speed = backup_set_speed,
|
||||||
};
|
};
|
||||||
|
@ -528,6 +537,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||||
|
|
||||||
job->backup_top = backup_top;
|
job->backup_top = backup_top;
|
||||||
job->source_bs = bs;
|
job->source_bs = bs;
|
||||||
|
job->target_bs = target;
|
||||||
job->on_source_error = on_source_error;
|
job->on_source_error = on_source_error;
|
||||||
job->on_target_error = on_target_error;
|
job->on_target_error = on_target_error;
|
||||||
job->sync_mode = sync_mode;
|
job->sync_mode = sync_mode;
|
||||||
|
|
11
block/io.c
11
block/io.c
|
@ -3460,3 +3460,14 @@ out:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_cancel_in_flight(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
if (!bs || !bs->drv) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->drv->bdrv_cancel_in_flight) {
|
||||||
|
bs->drv->bdrv_cancel_in_flight(bs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1179,6 +1179,14 @@ static bool mirror_drained_poll(BlockJob *job)
|
||||||
return !!s->in_flight;
|
return !!s->in_flight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mirror_cancel(Job *job)
|
||||||
|
{
|
||||||
|
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
|
||||||
|
BlockDriverState *target = blk_bs(s->target);
|
||||||
|
|
||||||
|
bdrv_cancel_in_flight(target);
|
||||||
|
}
|
||||||
|
|
||||||
static const BlockJobDriver mirror_job_driver = {
|
static const BlockJobDriver mirror_job_driver = {
|
||||||
.job_driver = {
|
.job_driver = {
|
||||||
.instance_size = sizeof(MirrorBlockJob),
|
.instance_size = sizeof(MirrorBlockJob),
|
||||||
|
@ -1190,6 +1198,7 @@ static const BlockJobDriver mirror_job_driver = {
|
||||||
.abort = mirror_abort,
|
.abort = mirror_abort,
|
||||||
.pause = mirror_pause,
|
.pause = mirror_pause,
|
||||||
.complete = mirror_complete,
|
.complete = mirror_complete,
|
||||||
|
.cancel = mirror_cancel,
|
||||||
},
|
},
|
||||||
.drained_poll = mirror_drained_poll,
|
.drained_poll = mirror_drained_poll,
|
||||||
};
|
};
|
||||||
|
|
15
block/nbd.c
15
block/nbd.c
|
@ -2458,6 +2458,18 @@ static const char *const nbd_strong_runtime_opts[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void nbd_cancel_in_flight(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
|
||||||
|
|
||||||
|
reconnect_delay_timer_del(s);
|
||||||
|
|
||||||
|
if (s->state == NBD_CLIENT_CONNECTING_WAIT) {
|
||||||
|
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
|
||||||
|
qemu_co_queue_restart_all(&s->free_sema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_nbd = {
|
static BlockDriver bdrv_nbd = {
|
||||||
.format_name = "nbd",
|
.format_name = "nbd",
|
||||||
.protocol_name = "nbd",
|
.protocol_name = "nbd",
|
||||||
|
@ -2484,6 +2496,7 @@ static BlockDriver bdrv_nbd = {
|
||||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||||
.bdrv_dirname = nbd_dirname,
|
.bdrv_dirname = nbd_dirname,
|
||||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||||
|
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_nbd_tcp = {
|
static BlockDriver bdrv_nbd_tcp = {
|
||||||
|
@ -2512,6 +2525,7 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||||
.bdrv_dirname = nbd_dirname,
|
.bdrv_dirname = nbd_dirname,
|
||||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||||
|
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_nbd_unix = {
|
static BlockDriver bdrv_nbd_unix = {
|
||||||
|
@ -2540,6 +2554,7 @@ static BlockDriver bdrv_nbd_unix = {
|
||||||
.bdrv_co_block_status = nbd_client_co_block_status,
|
.bdrv_co_block_status = nbd_client_co_block_status,
|
||||||
.bdrv_dirname = nbd_dirname,
|
.bdrv_dirname = nbd_dirname,
|
||||||
.strong_runtime_opts = nbd_strong_runtime_opts,
|
.strong_runtime_opts = nbd_strong_runtime_opts,
|
||||||
|
.bdrv_cancel_in_flight = nbd_cancel_in_flight,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_nbd_init(void)
|
static void bdrv_nbd_init(void)
|
||||||
|
|
|
@ -575,6 +575,11 @@ static const char *const raw_strong_runtime_opts[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void raw_cancel_in_flight(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
bdrv_cancel_in_flight(bs->file->bs);
|
||||||
|
}
|
||||||
|
|
||||||
BlockDriver bdrv_raw = {
|
BlockDriver bdrv_raw = {
|
||||||
.format_name = "raw",
|
.format_name = "raw",
|
||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
|
@ -608,6 +613,7 @@ BlockDriver bdrv_raw = {
|
||||||
.bdrv_has_zero_init = &raw_has_zero_init,
|
.bdrv_has_zero_init = &raw_has_zero_init,
|
||||||
.strong_runtime_opts = raw_strong_runtime_opts,
|
.strong_runtime_opts = raw_strong_runtime_opts,
|
||||||
.mutable_opts = mutable_opts,
|
.mutable_opts = mutable_opts,
|
||||||
|
.bdrv_cancel_in_flight = raw_cancel_in_flight,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_raw_init(void)
|
static void bdrv_raw_init(void)
|
||||||
|
|
|
@ -134,7 +134,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||||
qio_net_listener_set_name(nbd_server->listener,
|
qio_net_listener_set_name(nbd_server->listener,
|
||||||
"nbd-listener");
|
"nbd-listener");
|
||||||
|
|
||||||
if (qio_net_listener_open_sync(nbd_server->listener, addr, 1, errp) < 0) {
|
/*
|
||||||
|
* Because this server is persistent, a backlog of SOMAXCONN is
|
||||||
|
* better than trying to size it to max_connections.
|
||||||
|
*/
|
||||||
|
if (qio_net_listener_open_sync(nbd_server->listener, addr, SOMAXCONN,
|
||||||
|
errp) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,8 +136,8 @@ driver options if ``--image-opts`` is specified.
|
||||||
.. option:: -e, --shared=NUM
|
.. option:: -e, --shared=NUM
|
||||||
|
|
||||||
Allow up to *NUM* clients to share the device (default
|
Allow up to *NUM* clients to share the device (default
|
||||||
``1``). Safe for readers, but for now, consistency is not
|
``1``), 0 for unlimited. Safe for readers, but for now,
|
||||||
guaranteed between multiple writers.
|
consistency is not guaranteed between multiple writers.
|
||||||
|
|
||||||
.. option:: -t, --persistent
|
.. option:: -t, --persistent
|
||||||
|
|
||||||
|
|
|
@ -849,4 +849,7 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
|
||||||
BdrvChild *dst, int64_t dst_offset,
|
BdrvChild *dst, int64_t dst_offset,
|
||||||
int64_t bytes, BdrvRequestFlags read_flags,
|
int64_t bytes, BdrvRequestFlags read_flags,
|
||||||
BdrvRequestFlags write_flags);
|
BdrvRequestFlags write_flags);
|
||||||
|
|
||||||
|
void bdrv_cancel_in_flight(BlockDriverState *bs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -352,6 +352,15 @@ struct BlockDriver {
|
||||||
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
|
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
|
||||||
int64_t *map, BlockDriverState **file);
|
int64_t *map, BlockDriverState **file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This informs the driver that we are no longer interested in the result
|
||||||
|
* of in-flight requests, so don't waste the time if possible.
|
||||||
|
*
|
||||||
|
* One example usage is to avoid waiting for an nbd target node reconnect
|
||||||
|
* timeout during job-cancel.
|
||||||
|
*/
|
||||||
|
void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalidate any cached meta-data.
|
* Invalidate any cached meta-data.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -251,6 +251,11 @@ struct JobDriver {
|
||||||
*/
|
*/
|
||||||
void (*clean)(Job *job);
|
void (*clean)(Job *job);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the callback is not NULL, it will be invoked in job_cancel_async
|
||||||
|
*/
|
||||||
|
void (*cancel)(Job *job);
|
||||||
|
|
||||||
|
|
||||||
/** Called when the job is freed */
|
/** Called when the job is freed */
|
||||||
void (*free)(Job *job);
|
void (*free)(Job *job);
|
||||||
|
|
|
@ -202,8 +202,7 @@ int qio_channel_readv_full_all(QIOChannel *ioc,
|
||||||
int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
|
int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
error_prepend(errp,
|
error_setg(errp, "Unexpected end-of-file before all data were read");
|
||||||
"Unexpected end-of-file before all data were read.");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
|
|
3
job.c
3
job.c
|
@ -715,6 +715,9 @@ static int job_finalize_single(Job *job)
|
||||||
|
|
||||||
static void job_cancel_async(Job *job, bool force)
|
static void job_cancel_async(Job *job, bool force)
|
||||||
{
|
{
|
||||||
|
if (job->driver->cancel) {
|
||||||
|
job->driver->cancel(job);
|
||||||
|
}
|
||||||
if (job->user_paused) {
|
if (job->user_paused) {
|
||||||
/* Do not call job_enter here, the caller will handle it. */
|
/* Do not call job_enter here, the caller will handle it. */
|
||||||
if (job->driver->user_resume) {
|
if (job->driver->user_resume) {
|
||||||
|
|
14
qemu-nbd.c
14
qemu-nbd.c
|
@ -328,7 +328,7 @@ static void *nbd_client_thread(void *arg)
|
||||||
|
|
||||||
static int nbd_can_accept(void)
|
static int nbd_can_accept(void)
|
||||||
{
|
{
|
||||||
return state == RUNNING && nb_fds < shared;
|
return state == RUNNING && (shared == 0 || nb_fds < shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbd_update_server_watch(void);
|
static void nbd_update_server_watch(void);
|
||||||
|
@ -707,7 +707,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 ||
|
if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 ||
|
||||||
shared < 1) {
|
shared < 0) {
|
||||||
error_report("Invalid shared device number '%s'", optarg);
|
error_report("Invalid shared device number '%s'", optarg);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -964,8 +964,16 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
server = qio_net_listener_new();
|
server = qio_net_listener_new();
|
||||||
if (socket_activation == 0) {
|
if (socket_activation == 0) {
|
||||||
|
int backlog;
|
||||||
|
|
||||||
|
if (persistent || shared == 0) {
|
||||||
|
backlog = SOMAXCONN;
|
||||||
|
} else {
|
||||||
|
backlog = MIN(shared, SOMAXCONN);
|
||||||
|
}
|
||||||
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
||||||
if (qio_net_listener_open_sync(server, saddr, 1, &local_err) < 0) {
|
if (qio_net_listener_open_sync(server, saddr, backlog,
|
||||||
|
&local_err) < 0) {
|
||||||
object_unref(OBJECT(server));
|
object_unref(OBJECT(server));
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
|
@ -182,7 +182,7 @@ Job failed: The requested file size is too large
|
||||||
=== Resize image with invalid sizes ===
|
=== Resize image with invalid sizes ===
|
||||||
|
|
||||||
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}}
|
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}}
|
||||||
{"error": {"class": "GenericError", "desc": "Required too big image size, it must be not greater than 9223372035781033984"}}
|
{"error": {"class": "GenericError", "desc": "offset(9223372036854775296) exceeds maximum(9223372035781033984)"}}
|
||||||
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}}
|
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}}
|
||||||
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
|
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
|
||||||
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}}
|
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}}
|
||||||
|
|
|
@ -20,60 +20,102 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
import iotests
|
import iotests
|
||||||
from iotests import qemu_img_create, file_path, qemu_nbd_popen, log
|
from iotests import qemu_img_create, file_path, qemu_nbd_popen
|
||||||
|
|
||||||
iotests.script_initialize(
|
|
||||||
supported_fmts=['qcow2'],
|
|
||||||
)
|
|
||||||
|
|
||||||
disk_a, disk_b, nbd_sock = file_path('disk_a', 'disk_b', 'nbd-sock')
|
disk_a, disk_b, nbd_sock = file_path('disk_a', 'disk_b', 'nbd-sock')
|
||||||
nbd_uri = 'nbd+unix:///?socket=' + nbd_sock
|
nbd_uri = 'nbd+unix:///?socket=' + nbd_sock
|
||||||
size = 5 * 1024 * 1024
|
|
||||||
wait_limit = 3.0
|
wait_limit = 3.0
|
||||||
wait_step = 0.2
|
wait_step = 0.2
|
||||||
|
|
||||||
qemu_img_create('-f', iotests.imgfmt, disk_a, str(size))
|
|
||||||
qemu_img_create('-f', iotests.imgfmt, disk_b, str(size))
|
|
||||||
|
|
||||||
with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b):
|
class TestNbdReconnect(iotests.QMPTestCase):
|
||||||
vm = iotests.VM().add_drive(disk_a)
|
def init_vm(self, disk_size):
|
||||||
vm.launch()
|
qemu_img_create('-f', iotests.imgfmt, disk_a, str(disk_size))
|
||||||
vm.hmp_qemu_io('drive0', 'write 0 {}'.format(size))
|
qemu_img_create('-f', iotests.imgfmt, disk_b, str(disk_size))
|
||||||
|
self.vm = iotests.VM().add_drive(disk_a)
|
||||||
|
self.vm.launch()
|
||||||
|
self.vm.hmp_qemu_io('drive0', 'write 0 {}'.format(disk_size))
|
||||||
|
|
||||||
vm.qmp_log('blockdev-add', filters=[iotests.filter_qmp_testfiles],
|
def tearDown(self):
|
||||||
**{'node_name': 'backup0',
|
self.vm.shutdown()
|
||||||
'driver': 'raw',
|
os.remove(disk_a)
|
||||||
'file': {'driver': 'nbd',
|
os.remove(disk_b)
|
||||||
'server': {'type': 'unix', 'path': nbd_sock},
|
|
||||||
'reconnect-delay': 10}})
|
|
||||||
vm.qmp_log('blockdev-backup', device='drive0', sync='full',
|
|
||||||
target='backup0', speed=(1 * 1024 * 1024))
|
|
||||||
|
|
||||||
# Wait for some progress
|
def start_job(self, job):
|
||||||
t = 0.0
|
"""Stat job with nbd target and kill the server"""
|
||||||
while t < wait_limit:
|
assert job in ('blockdev-backup', 'blockdev-mirror')
|
||||||
jobs = vm.qmp('query-block-jobs')['return']
|
with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b):
|
||||||
if jobs and jobs[0]['offset'] > 0:
|
result = self.vm.qmp('blockdev-add',
|
||||||
break
|
**{'node_name': 'backup0',
|
||||||
time.sleep(wait_step)
|
'driver': 'raw',
|
||||||
t += wait_step
|
'file': {'driver': 'nbd',
|
||||||
|
'server': {'type': 'unix',
|
||||||
|
'path': nbd_sock},
|
||||||
|
'reconnect-delay': 10}})
|
||||||
|
self.assert_qmp(result, 'return', {})
|
||||||
|
result = self.vm.qmp(job, device='drive0',
|
||||||
|
sync='full', target='backup0',
|
||||||
|
speed=(1 * 1024 * 1024))
|
||||||
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
if jobs and jobs[0]['offset'] > 0:
|
# Wait for some progress
|
||||||
log('Backup job is started')
|
t = 0.0
|
||||||
|
while t < wait_limit:
|
||||||
|
jobs = self.vm.qmp('query-block-jobs')['return']
|
||||||
|
if jobs and jobs[0]['offset'] > 0:
|
||||||
|
break
|
||||||
|
time.sleep(wait_step)
|
||||||
|
t += wait_step
|
||||||
|
|
||||||
jobs = vm.qmp('query-block-jobs')['return']
|
self.assertTrue(jobs and jobs[0]['offset'] > 0) # job started
|
||||||
if jobs and jobs[0]['offset'] < jobs[0]['len']:
|
|
||||||
log('Backup job is still in progress')
|
|
||||||
|
|
||||||
vm.qmp_log('block-job-set-speed', device='drive0', speed=0)
|
jobs = self.vm.qmp('query-block-jobs')['return']
|
||||||
|
# Check that job is still in progress
|
||||||
|
self.assertTrue(jobs)
|
||||||
|
self.assertTrue(jobs[0]['offset'] < jobs[0]['len'])
|
||||||
|
|
||||||
# Emulate server down time for 1 second
|
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0)
|
||||||
time.sleep(1)
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b):
|
# Emulate server down time for 1 second
|
||||||
e = vm.event_wait('BLOCK_JOB_COMPLETED')
|
time.sleep(1)
|
||||||
log('Backup completed: {}'.format(e['data']['offset']))
|
|
||||||
vm.qmp_log('blockdev-del', node_name='backup0')
|
def test_backup(self):
|
||||||
vm.shutdown()
|
size = 5 * 1024 * 1024
|
||||||
|
self.init_vm(size)
|
||||||
|
self.start_job('blockdev-backup')
|
||||||
|
|
||||||
|
with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk_b):
|
||||||
|
e = self.vm.event_wait('BLOCK_JOB_COMPLETED')
|
||||||
|
self.assertEqual(e['data']['offset'], size)
|
||||||
|
result = self.vm.qmp('blockdev-del', node_name='backup0')
|
||||||
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
|
def cancel_job(self):
|
||||||
|
result = self.vm.qmp('block-job-cancel', device='drive0')
|
||||||
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
|
start_t = time.time()
|
||||||
|
self.vm.event_wait('BLOCK_JOB_CANCELLED')
|
||||||
|
delta_t = time.time() - start_t
|
||||||
|
self.assertTrue(delta_t < 2.0)
|
||||||
|
|
||||||
|
def test_mirror_cancel(self):
|
||||||
|
# Mirror speed limit doesn't work well enough, it seems that mirror
|
||||||
|
# will run many parallel requests anyway. MAX_IN_FLIGHT is 16 and
|
||||||
|
# MAX_IO_BYTES is 1M in mirror.c, so let's use 20M disk.
|
||||||
|
self.init_vm(20 * 1024 * 1024)
|
||||||
|
self.start_job('blockdev-mirror')
|
||||||
|
self.cancel_job()
|
||||||
|
|
||||||
|
def test_backup_cancel(self):
|
||||||
|
self.init_vm(5 * 1024 * 1024)
|
||||||
|
self.start_job('blockdev-backup')
|
||||||
|
self.cancel_job()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
iotests.main(supported_fmts=['qcow2'])
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
Start NBD server
|
...
|
||||||
{"execute": "blockdev-add", "arguments": {"driver": "raw", "file": {"driver": "nbd", "reconnect-delay": 10, "server": {"path": "TEST_DIR/PID-nbd-sock", "type": "unix"}}, "node-name": "backup0"}}
|
----------------------------------------------------------------------
|
||||||
{"return": {}}
|
Ran 3 tests
|
||||||
{"execute": "blockdev-backup", "arguments": {"device": "drive0", "speed": 1048576, "sync": "full", "target": "backup0"}}
|
|
||||||
{"return": {}}
|
OK
|
||||||
Backup job is started
|
|
||||||
Kill NBD server
|
|
||||||
Backup job is still in progress
|
|
||||||
{"execute": "block-job-set-speed", "arguments": {"device": "drive0", "speed": 0}}
|
|
||||||
{"return": {}}
|
|
||||||
Start NBD server
|
|
||||||
Backup completed: 5242880
|
|
||||||
{"execute": "blockdev-del", "arguments": {"node-name": "backup0"}}
|
|
||||||
{"return": {}}
|
|
||||||
Kill NBD server
|
|
||||||
|
|
|
@ -296,7 +296,9 @@ def qemu_nbd_list_log(*args: str) -> str:
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def qemu_nbd_popen(*args):
|
def qemu_nbd_popen(*args):
|
||||||
'''Context manager running qemu-nbd within the context'''
|
'''Context manager running qemu-nbd within the context'''
|
||||||
pid_file = file_path("pid")
|
pid_file = file_path("qemu_nbd_popen-nbd-pid-file")
|
||||||
|
|
||||||
|
assert not os.path.exists(pid_file)
|
||||||
|
|
||||||
cmd = list(qemu_nbd_args)
|
cmd = list(qemu_nbd_args)
|
||||||
cmd.extend(('--persistent', '--pid-file', pid_file))
|
cmd.extend(('--persistent', '--pid-file', pid_file))
|
||||||
|
@ -314,6 +316,8 @@ def qemu_nbd_popen(*args):
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
if os.path.exists(pid_file):
|
||||||
|
os.remove(pid_file)
|
||||||
log('Kill NBD server')
|
log('Kill NBD server')
|
||||||
p.kill()
|
p.kill()
|
||||||
p.wait()
|
p.wait()
|
||||||
|
|
Loading…
Reference in New Issue