mirror of https://github.com/proxmox/mirror_qemu
Block layer patches:
- qemu-img convert -C is now required to enable copy offloading - file-posix: Fix write_zeroes with unmap on block devices (would fall back to explicit writes on recent kernels) - Fix query-blockstats interface for use with -blockdev - Minor fixes and documentation updates -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbXyneAAoJEH8JsnLIjy/WQ8YQAKZgEMeFIp/MmYuyqCzjUKux lNgM6MrwSSLqDnnyHLMjXL2LLEzeLQzrY47lLAS9e2rZUQhPj7enebNr1mIGW2lk +qd0nQualADNEjV91WwwnGs/vvs9ApPtQNGsUhAo4B+vAD9xkKVTPGZr1lAE40l5 3rIfmFO9DjYXmQD49bqqfEMZrcpgHLHGPCEECgdPCg08OZxm7rLm7KzEh/IYDKeB mdGNe1xTraYXvGLXZSCWrZUH2P6pLNVoifoWhT4AyGuw+sz9SZGTA0I2jNHIUtYQ 4CKPtvKibPEO3RcYXLMuzzUTmmWMwyv5WJne1k7no735D0ZYsfro9E7wSNb+h8FQ Ragh+QgHgssx/ttDsVdnpXY15PJjgxAtxX3qcXDP8t9TYtjAiu3HrjtHDUWT+24x kME4zURg5Lyf2C+9JLl30SLDnLgdA7hdP+cv4Gbn2AHs+Z32suZX02adMj7iBqVZ YtSWxdX7TspavOjwAj4B4KMiFt+apOOu+zm3iy0Gf87x5QjdiUHKirr88rMUYrxu 3dZwnXZi+gok4NCiHzQmJx23j/vGuUyrMR5hPKtvDfKY7znQl0vm/FfNMlbNn0i1 hZCjiTYUVkOgvbTI5YXhvYKAFVQF0fifyMVvuWMFMC9vHdQxWS6k61XDYDpjgCup vXRRjhkohy/FLlM/vNVU =1IKa -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - qemu-img convert -C is now required to enable copy offloading - file-posix: Fix write_zeroes with unmap on block devices (would fall back to explicit writes on recent kernels) - Fix query-blockstats interface for use with -blockdev - Minor fixes and documentation updates # gpg: Signature made Mon 30 Jul 2018 16:08:14 BST # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: qemu-iotests: Test query-blockstats with -drive and -blockdev block/qapi: Include anonymous BBs in query-blockstats block/qapi: Add 'qdev' field to query-blockstats result file-posix: Fix write_zeroes with unmap on block devices block: Fix documentation for BDRV_REQ_MAY_UNMAP iotests: Add test for 'qemu-img convert -C' compatibility qemu-img: Add -C option for convert with copy offloading Revert "qemu-img: Document copy offloading implications with -S and -c" iotests: Don't lock /dev/null in 226 docs: Describe using images in writing iotests file-posix: Handle EINTR in preallocation=full write qcow2: A grammar fix in conflicting cache sizing error message qcow: fix a reference leak Signed-off-by: Peter Maydell <peter.maydell@linaro.org>master
commit
7b799ec696
|
@ -648,7 +648,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bs->supported_zero_flags = s->discard_zeroes ? BDRV_REQ_MAY_UNMAP : 0;
|
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||||
|
@ -1487,6 +1487,35 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t handle_aiocb_write_zeroes_unmap(RawPosixAIOData *aiocb)
|
||||||
|
{
|
||||||
|
BDRVRawState *s G_GNUC_UNUSED = aiocb->bs->opaque;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* First try to write zeros and unmap at the same time */
|
||||||
|
|
||||||
|
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
|
||||||
|
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||||
|
aiocb->aio_offset, aiocb->aio_nbytes);
|
||||||
|
if (ret != -ENOTSUP) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_XFS
|
||||||
|
if (s->is_xfs) {
|
||||||
|
/* xfs_discard() guarantees that the discarded area reads as all-zero
|
||||||
|
* afterwards, so we can use it here. */
|
||||||
|
return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we couldn't manage to unmap while guaranteed that the area reads as
|
||||||
|
* all-zero afterwards, just write zeroes without unmapping */
|
||||||
|
ret = handle_aiocb_write_zeroes(aiocb);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_COPY_FILE_RANGE
|
#ifndef HAVE_COPY_FILE_RANGE
|
||||||
static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
||||||
off_t *out_off, size_t len, unsigned int flags)
|
off_t *out_off, size_t len, unsigned int flags)
|
||||||
|
@ -1646,6 +1675,9 @@ static int handle_aiocb_truncate(RawPosixAIOData *aiocb)
|
||||||
num = MIN(left, 65536);
|
num = MIN(left, 65536);
|
||||||
result = write(fd, buf, num);
|
result = write(fd, buf, num);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
result = -errno;
|
result = -errno;
|
||||||
error_setg_errno(errp, -result,
|
error_setg_errno(errp, -result,
|
||||||
"Could not write zeros for preallocation");
|
"Could not write zeros for preallocation");
|
||||||
|
@ -1729,6 +1761,9 @@ static int aio_worker(void *arg)
|
||||||
case QEMU_AIO_WRITE_ZEROES:
|
case QEMU_AIO_WRITE_ZEROES:
|
||||||
ret = handle_aiocb_write_zeroes(aiocb);
|
ret = handle_aiocb_write_zeroes(aiocb);
|
||||||
break;
|
break;
|
||||||
|
case QEMU_AIO_WRITE_ZEROES | QEMU_AIO_DISCARD:
|
||||||
|
ret = handle_aiocb_write_zeroes_unmap(aiocb);
|
||||||
|
break;
|
||||||
case QEMU_AIO_COPY_RANGE:
|
case QEMU_AIO_COPY_RANGE:
|
||||||
ret = handle_aiocb_copy_range(aiocb);
|
ret = handle_aiocb_copy_range(aiocb);
|
||||||
break;
|
break;
|
||||||
|
@ -2553,15 +2588,13 @@ static int coroutine_fn raw_co_pwrite_zeroes(
|
||||||
int bytes, BdrvRequestFlags flags)
|
int bytes, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
|
int operation = QEMU_AIO_WRITE_ZEROES;
|
||||||
|
|
||||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||||
return paio_submit_co(bs, s->fd, offset, NULL, bytes,
|
operation |= QEMU_AIO_DISCARD;
|
||||||
QEMU_AIO_WRITE_ZEROES);
|
|
||||||
} else if (s->discard_zeroes) {
|
|
||||||
return paio_submit_co(bs, s->fd, offset, NULL, bytes,
|
|
||||||
QEMU_AIO_DISCARD);
|
|
||||||
}
|
}
|
||||||
return -ENOTSUP;
|
|
||||||
|
return paio_submit_co(bs, s->fd, offset, NULL, bytes, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
@ -3054,20 +3087,19 @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
|
||||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
|
int operation = QEMU_AIO_WRITE_ZEROES | QEMU_AIO_BLKDEV;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = fd_open(bs);
|
rc = fd_open(bs);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
|
||||||
return paio_submit_co(bs, s->fd, offset, NULL, bytes,
|
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||||
QEMU_AIO_WRITE_ZEROES|QEMU_AIO_BLKDEV);
|
operation |= QEMU_AIO_DISCARD;
|
||||||
} else if (s->discard_zeroes) {
|
|
||||||
return paio_submit_co(bs, s->fd, offset, NULL, bytes,
|
|
||||||
QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
|
||||||
}
|
}
|
||||||
return -ENOTSUP;
|
|
||||||
|
return paio_submit_co(bs, s->fd, offset, NULL, bytes, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
|
static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
|
||||||
|
|
16
block/qapi.c
16
block/qapi.c
|
@ -593,15 +593,29 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
|
||||||
p_next = &info->next;
|
p_next = &info->next;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
|
||||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||||
AioContext *ctx = blk_get_aio_context(blk);
|
AioContext *ctx = blk_get_aio_context(blk);
|
||||||
BlockStats *s;
|
BlockStats *s;
|
||||||
|
char *qdev;
|
||||||
|
|
||||||
|
if (!*blk_name(blk) && !blk_get_attached_dev(blk)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
aio_context_acquire(ctx);
|
aio_context_acquire(ctx);
|
||||||
s = bdrv_query_bds_stats(blk_bs(blk), true);
|
s = bdrv_query_bds_stats(blk_bs(blk), true);
|
||||||
s->has_device = true;
|
s->has_device = true;
|
||||||
s->device = g_strdup(blk_name(blk));
|
s->device = g_strdup(blk_name(blk));
|
||||||
|
|
||||||
|
qdev = blk_get_attached_dev_id(blk);
|
||||||
|
if (qdev && *qdev) {
|
||||||
|
s->has_qdev = true;
|
||||||
|
s->qdev = qdev;
|
||||||
|
} else {
|
||||||
|
g_free(qdev);
|
||||||
|
}
|
||||||
|
|
||||||
bdrv_query_blk_stats(s->stats, blk);
|
bdrv_query_blk_stats(s->stats, blk);
|
||||||
aio_context_release(ctx);
|
aio_context_release(ctx);
|
||||||
|
|
||||||
|
|
|
@ -938,6 +938,7 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
exit:
|
exit:
|
||||||
blk_unref(qcow_blk);
|
blk_unref(qcow_blk);
|
||||||
|
bdrv_unref(bs);
|
||||||
qcrypto_block_free(crypto);
|
qcrypto_block_free(crypto);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -797,7 +797,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
|
||||||
if (l2_cache_size_set && refcount_cache_size_set) {
|
if (l2_cache_size_set && refcount_cache_size_set) {
|
||||||
error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
|
error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
|
||||||
" and " QCOW2_OPT_REFCOUNT_CACHE_SIZE " may not be set "
|
" and " QCOW2_OPT_REFCOUNT_CACHE_SIZE " may not be set "
|
||||||
"the same time");
|
"at the same time");
|
||||||
return;
|
return;
|
||||||
} else if (*l2_cache_size > combined_cache_size) {
|
} else if (*l2_cache_size > combined_cache_size) {
|
||||||
error_setg(errp, QCOW2_OPT_L2_CACHE_SIZE " may not exceed "
|
error_setg(errp, QCOW2_OPT_L2_CACHE_SIZE " may not exceed "
|
||||||
|
|
|
@ -255,6 +255,17 @@ comparable library support for invoking and interacting with QEMU programs. If
|
||||||
you opt for Python, it is strongly recommended to write Python 3 compatible
|
you opt for Python, it is strongly recommended to write Python 3 compatible
|
||||||
code.
|
code.
|
||||||
|
|
||||||
|
Both Python and Bash frameworks in iotests provide helpers to manage test
|
||||||
|
images. They can be used to create and clean up images under the test
|
||||||
|
directory. If no I/O or any protocol specific feature is needed, it is often
|
||||||
|
more convenient to use the pseudo block driver, ``null-co://``, as the test
|
||||||
|
image, which doesn't require image creation or cleaning up. Avoid system-wide
|
||||||
|
devices or files whenever possible, such as ``/dev/null`` or ``/dev/zero``.
|
||||||
|
Otherwise, image locking implications have to be considered. For example,
|
||||||
|
another application on the host may have locked the file, possibly leading to a
|
||||||
|
test failure. If using such devices are explicitly desired, consider adding
|
||||||
|
``locking=off`` option to disable image locking.
|
||||||
|
|
||||||
Docker based tests
|
Docker based tests
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,12 @@ typedef struct BlockFragInfo {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BDRV_REQ_COPY_ON_READ = 0x1,
|
BDRV_REQ_COPY_ON_READ = 0x1,
|
||||||
BDRV_REQ_ZERO_WRITE = 0x2,
|
BDRV_REQ_ZERO_WRITE = 0x2,
|
||||||
/* The BDRV_REQ_MAY_UNMAP flag is used to indicate that the block driver
|
|
||||||
* is allowed to optimize a write zeroes request by unmapping (discarding)
|
/*
|
||||||
* blocks if it is guaranteed that the result will read back as
|
* The BDRV_REQ_MAY_UNMAP flag is used in write_zeroes requests to indicate
|
||||||
* zeroes. The flag is only passed to the driver if the block device is
|
* that the block driver should unmap (discard) blocks if it is guaranteed
|
||||||
* opened with BDRV_O_UNMAP.
|
* that the result will read back as zeroes. The flag is only passed to the
|
||||||
|
* driver if the block device is opened with BDRV_O_UNMAP.
|
||||||
*/
|
*/
|
||||||
BDRV_REQ_MAY_UNMAP = 0x4,
|
BDRV_REQ_MAY_UNMAP = 0x4,
|
||||||
|
|
||||||
|
|
|
@ -866,6 +866,9 @@
|
||||||
#
|
#
|
||||||
# @node-name: The node name of the device. (Since 2.3)
|
# @node-name: The node name of the device. (Since 2.3)
|
||||||
#
|
#
|
||||||
|
# @qdev: The qdev ID, or if no ID is assigned, the QOM path of the block
|
||||||
|
# device. (since 3.0)
|
||||||
|
#
|
||||||
# @stats: A @BlockDeviceStats for the device.
|
# @stats: A @BlockDeviceStats for the device.
|
||||||
#
|
#
|
||||||
# @parent: This describes the file block device if it has one.
|
# @parent: This describes the file block device if it has one.
|
||||||
|
@ -879,7 +882,7 @@
|
||||||
# Since: 0.14.0
|
# Since: 0.14.0
|
||||||
##
|
##
|
||||||
{ 'struct': 'BlockStats',
|
{ 'struct': 'BlockStats',
|
||||||
'data': {'*device': 'str', '*node-name': 'str',
|
'data': {'*device': 'str', '*qdev': 'str', '*node-name': 'str',
|
||||||
'stats': 'BlockDeviceStats',
|
'stats': 'BlockDeviceStats',
|
||||||
'*parent': 'BlockStats',
|
'*parent': 'BlockStats',
|
||||||
'*backing': 'BlockStats'} }
|
'*backing': 'BlockStats'} }
|
||||||
|
@ -941,7 +944,8 @@
|
||||||
# "idle_time_ns":2953431879,
|
# "idle_time_ns":2953431879,
|
||||||
# "account_invalid":true,
|
# "account_invalid":true,
|
||||||
# "account_failed":false
|
# "account_failed":false
|
||||||
# }
|
# },
|
||||||
|
# "qdev": "/machine/unattached/device[23]"
|
||||||
# },
|
# },
|
||||||
# {
|
# {
|
||||||
# "device":"ide1-cd0",
|
# "device":"ide1-cd0",
|
||||||
|
@ -959,7 +963,8 @@
|
||||||
# "wr_merged":0,
|
# "wr_merged":0,
|
||||||
# "account_invalid":false,
|
# "account_invalid":false,
|
||||||
# "account_failed":false
|
# "account_failed":false
|
||||||
# }
|
# },
|
||||||
|
# "qdev": "/machine/unattached/device[24]"
|
||||||
# },
|
# },
|
||||||
# {
|
# {
|
||||||
# "device":"floppy0",
|
# "device":"floppy0",
|
||||||
|
@ -977,7 +982,8 @@
|
||||||
# "wr_merged":0,
|
# "wr_merged":0,
|
||||||
# "account_invalid":false,
|
# "account_invalid":false,
|
||||||
# "account_failed":false
|
# "account_failed":false
|
||||||
# }
|
# },
|
||||||
|
# "qdev": "/machine/unattached/device[16]"
|
||||||
# },
|
# },
|
||||||
# {
|
# {
|
||||||
# "device":"sd0",
|
# "device":"sd0",
|
||||||
|
|
|
@ -44,7 +44,7 @@ STEXI
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
DEF("convert", img_convert,
|
DEF("convert", img_convert,
|
||||||
"convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
|
"convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
|
||||||
STEXI
|
STEXI
|
||||||
@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
21
qemu-img.c
21
qemu-img.c
|
@ -2024,11 +2024,12 @@ static int img_convert(int argc, char **argv)
|
||||||
skip_create = false, progress = false, tgt_image_opts = false;
|
skip_create = false, progress = false, tgt_image_opts = false;
|
||||||
int64_t ret = -EINVAL;
|
int64_t ret = -EINVAL;
|
||||||
bool force_share = false;
|
bool force_share = false;
|
||||||
|
bool explict_min_sparse = false;
|
||||||
|
|
||||||
ImgConvertState s = (ImgConvertState) {
|
ImgConvertState s = (ImgConvertState) {
|
||||||
/* Need at least 4k of zeros for sparse detection */
|
/* Need at least 4k of zeros for sparse detection */
|
||||||
.min_sparse = 8,
|
.min_sparse = 8,
|
||||||
.copy_range = true,
|
.copy_range = false,
|
||||||
.buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
|
.buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
|
||||||
.wr_in_order = true,
|
.wr_in_order = true,
|
||||||
.num_coroutines = 8,
|
.num_coroutines = 8,
|
||||||
|
@ -2043,7 +2044,7 @@ static int img_convert(int argc, char **argv)
|
||||||
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
|
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
c = getopt_long(argc, argv, ":hf:O:B:co:l:S:pt:T:qnm:WU",
|
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
|
||||||
long_options, NULL);
|
long_options, NULL);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
|
@ -2067,9 +2068,11 @@ static int img_convert(int argc, char **argv)
|
||||||
case 'B':
|
case 'B':
|
||||||
out_baseimg = optarg;
|
out_baseimg = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
s.copy_range = true;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
s.compressed = true;
|
s.compressed = true;
|
||||||
s.copy_range = false;
|
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (!is_valid_option_list(optarg)) {
|
if (!is_valid_option_list(optarg)) {
|
||||||
|
@ -2112,7 +2115,7 @@ static int img_convert(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.min_sparse = sval / BDRV_SECTOR_SIZE;
|
s.min_sparse = sval / BDRV_SECTOR_SIZE;
|
||||||
s.copy_range = false;
|
explict_min_sparse = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p':
|
case 'p':
|
||||||
|
@ -2172,6 +2175,16 @@ static int img_convert(int argc, char **argv)
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s.compressed && s.copy_range) {
|
||||||
|
error_report("Cannot enable copy offloading when -c is used");
|
||||||
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explict_min_sparse && s.copy_range) {
|
||||||
|
error_report("Cannot enable copy offloading when -S is used");
|
||||||
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
if (tgt_image_opts && !skip_create) {
|
if (tgt_image_opts && !skip_create) {
|
||||||
error_report("--target-image-opts requires use of -n flag");
|
error_report("--target-image-opts requires use of -n flag");
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
|
|
|
@ -96,8 +96,7 @@ will enumerate information about backing files in a disk image chain. Refer
|
||||||
below for further description.
|
below for further description.
|
||||||
|
|
||||||
@item -c
|
@item -c
|
||||||
indicates that target image must be compressed (qcow format only). If this
|
indicates that target image must be compressed (qcow format only)
|
||||||
option is used, copy offloading will not be attempted.
|
|
||||||
|
|
||||||
@item -h
|
@item -h
|
||||||
with or without a command shows help and lists the supported formats
|
with or without a command shows help and lists the supported formats
|
||||||
|
@ -116,8 +115,7 @@ in case both @var{-q} and @var{-p} options are used.
|
||||||
indicates the consecutive number of bytes that must contain only zeros
|
indicates the consecutive number of bytes that must contain only zeros
|
||||||
for qemu-img to create a sparse image during conversion. This value is rounded
|
for qemu-img to create a sparse image during conversion. This value is rounded
|
||||||
down to the nearest 512 bytes. You may use the common size suffixes like
|
down to the nearest 512 bytes. You may use the common size suffixes like
|
||||||
@code{k} for kilobytes. If this option is used, copy offloading will not be
|
@code{k} for kilobytes.
|
||||||
attempted.
|
|
||||||
|
|
||||||
@item -t @var{cache}
|
@item -t @var{cache}
|
||||||
specifies the cache mode that should be used with the (destination) file. See
|
specifies the cache mode that should be used with the (destination) file. See
|
||||||
|
@ -171,6 +169,12 @@ Number of parallel coroutines for the convert process
|
||||||
Allow out-of-order writes to the destination. This option improves performance,
|
Allow out-of-order writes to the destination. This option improves performance,
|
||||||
but is only recommended for preallocated devices like host devices or other
|
but is only recommended for preallocated devices like host devices or other
|
||||||
raw block devices.
|
raw block devices.
|
||||||
|
@item -C
|
||||||
|
Try to use copy offloading to move data from source image to target. This may
|
||||||
|
improve performance if the data is remote, such as with NFS or iSCSI backends,
|
||||||
|
but will not automatically sparsify zero sectors, and may result in a fully
|
||||||
|
allocated target image depending on the host support for getting allocation
|
||||||
|
information.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Parameters to dd subcommand:
|
Parameters to dd subcommand:
|
||||||
|
@ -321,7 +325,7 @@ Error on reading data
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||||
|
|
||||||
Convert the disk image @var{filename} or a snapshot @var{snapshot_param}
|
Convert the disk image @var{filename} or a snapshot @var{snapshot_param}
|
||||||
to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
|
to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
|
||||||
|
|
|
@ -157,6 +157,14 @@ run_qemu_img convert -o help
|
||||||
# Try help option for a format that does not support creation
|
# Try help option for a format that does not support creation
|
||||||
run_qemu_img convert -O bochs -o help
|
run_qemu_img convert -O bochs -o help
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === convert: -C and other options ===
|
||||||
|
|
||||||
|
# Adding the help option to a command without other -o options
|
||||||
|
run_qemu_img convert -C -S 4k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
|
||||||
|
run_qemu_img convert -C -S 8k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
|
||||||
|
run_qemu_img convert -C -c -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === amend: Options specified more than once ===
|
echo === amend: Options specified more than once ===
|
||||||
|
|
||||||
|
|
|
@ -508,6 +508,17 @@ size Virtual disk size
|
||||||
Testing: convert -O bochs -o help
|
Testing: convert -O bochs -o help
|
||||||
qemu-img: Format driver 'bochs' does not support image creation
|
qemu-img: Format driver 'bochs' does not support image creation
|
||||||
|
|
||||||
|
=== convert: -C and other options ===
|
||||||
|
|
||||||
|
Testing: convert -C -S 4k -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
|
||||||
|
qemu-img: Cannot enable copy offloading when -S is used
|
||||||
|
|
||||||
|
Testing: convert -C -S 8k -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
|
||||||
|
qemu-img: Cannot enable copy offloading when -S is used
|
||||||
|
|
||||||
|
Testing: convert -C -c -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
|
||||||
|
qemu-img: Cannot enable copy offloading when -c is used
|
||||||
|
|
||||||
=== amend: Options specified more than once ===
|
=== amend: Options specified more than once ===
|
||||||
|
|
||||||
Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2
|
Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2
|
||||||
|
|
|
@ -5,10 +5,10 @@ wrote 65536/65536 bytes at offset 0
|
||||||
|
|
||||||
=== Testing invalid option combinations ===
|
=== Testing invalid option combinations ===
|
||||||
|
|
||||||
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time
|
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set at the same time
|
||||||
can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size
|
can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size
|
||||||
can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size
|
can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size
|
||||||
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time
|
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set at the same time
|
||||||
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
||||||
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
||||||
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
|
||||||
|
|
|
@ -16,7 +16,7 @@ read 33554432/33554432 bytes at offset 0
|
||||||
=== Try setting some invalid values ===
|
=== Try setting some invalid values ===
|
||||||
|
|
||||||
Parameter 'lazy-refcounts' expects 'on' or 'off'
|
Parameter 'lazy-refcounts' expects 'on' or 'off'
|
||||||
cache-size, l2-cache-size and refcount-cache-size may not be set the same time
|
cache-size, l2-cache-size and refcount-cache-size may not be set at the same time
|
||||||
l2-cache-size may not exceed cache-size
|
l2-cache-size may not exceed cache-size
|
||||||
refcount-cache-size may not exceed cache-size
|
refcount-cache-size may not exceed cache-size
|
||||||
L2 cache size too big
|
L2 cache size too big
|
||||||
|
|
|
@ -56,10 +56,10 @@ for PROTO in "file" "host_device" "host_cdrom"; do
|
||||||
echo
|
echo
|
||||||
echo "== Testing RO =="
|
echo "== Testing RO =="
|
||||||
$QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
$QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||||
$QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt
|
$QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null,locking=off" 2>&1 | _filter_imgfmt
|
||||||
echo "== Testing RW =="
|
echo "== Testing RW =="
|
||||||
$QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
$QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||||
$QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt
|
$QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null,locking=off" 2>&1 | _filter_imgfmt
|
||||||
done
|
done
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test query-blockstats with different ways to create a BB
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 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=kwolf@redhat.com
|
||||||
|
|
||||||
|
seq=$(basename $0)
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=$PWD
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
_supported_fmt generic
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
function do_run_qemu()
|
||||||
|
{
|
||||||
|
echo Testing: "$@"
|
||||||
|
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_qemu()
|
||||||
|
{
|
||||||
|
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
|
||||||
|
| _filter_qemu | _filter_imgfmt \
|
||||||
|
| _filter_generated_node_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '=== blockstats with -drive if=virtio ==='
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu -drive driver=null-co,if=virtio <<EOF
|
||||||
|
{ "execute": "qmp_capabilities" }
|
||||||
|
{ "execute": "query-blockstats"}
|
||||||
|
{ "execute": "quit" }
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '=== blockstats with -drive if=none ==='
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu -drive driver=null-co,if=none <<EOF
|
||||||
|
{ "execute": "qmp_capabilities" }
|
||||||
|
{ "execute": "query-blockstats"}
|
||||||
|
{ "execute": "quit" }
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '=== blockstats with -blockdev ==='
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu -blockdev driver=null-co,node-name=null <<EOF
|
||||||
|
{ "execute": "qmp_capabilities" }
|
||||||
|
{ "execute": "query-blockstats"}
|
||||||
|
{ "execute": "quit" }
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '=== blockstats with -blockdev and -device ==='
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_qemu -blockdev driver=null-co,node-name=null -device virtio-blk,drive=null,id=virtio0 <<EOF
|
||||||
|
{ "execute": "qmp_capabilities" }
|
||||||
|
{ "execute": "query-blockstats"}
|
||||||
|
{ "execute": "quit" }
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,205 @@
|
||||||
|
QA output created by 227
|
||||||
|
|
||||||
|
=== blockstats with -drive if=virtio ===
|
||||||
|
|
||||||
|
Testing: -drive driver=null-co,if=virtio
|
||||||
|
{
|
||||||
|
QMP_VERSION
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
{
|
||||||
|
"device": "virtio0",
|
||||||
|
"stats": {
|
||||||
|
"flush_total_time_ns": 0,
|
||||||
|
"wr_highest_offset": 0,
|
||||||
|
"wr_total_time_ns": 0,
|
||||||
|
"failed_wr_operations": 0,
|
||||||
|
"failed_rd_operations": 0,
|
||||||
|
"wr_merged": 0,
|
||||||
|
"wr_bytes": 0,
|
||||||
|
"timed_stats": [
|
||||||
|
],
|
||||||
|
"failed_flush_operations": 0,
|
||||||
|
"account_invalid": true,
|
||||||
|
"rd_total_time_ns": 0,
|
||||||
|
"flush_operations": 0,
|
||||||
|
"wr_operations": 0,
|
||||||
|
"rd_merged": 0,
|
||||||
|
"rd_bytes": 0,
|
||||||
|
"invalid_flush_operations": 0,
|
||||||
|
"account_failed": true,
|
||||||
|
"rd_operations": 0,
|
||||||
|
"invalid_wr_operations": 0,
|
||||||
|
"invalid_rd_operations": 0
|
||||||
|
},
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"qdev": "/machine/peripheral-anon/device[0]/virtio-backend"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== blockstats with -drive if=none ===
|
||||||
|
|
||||||
|
Testing: -drive driver=null-co,if=none
|
||||||
|
{
|
||||||
|
QMP_VERSION
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
{
|
||||||
|
"device": "none0",
|
||||||
|
"stats": {
|
||||||
|
"flush_total_time_ns": 0,
|
||||||
|
"wr_highest_offset": 0,
|
||||||
|
"wr_total_time_ns": 0,
|
||||||
|
"failed_wr_operations": 0,
|
||||||
|
"failed_rd_operations": 0,
|
||||||
|
"wr_merged": 0,
|
||||||
|
"wr_bytes": 0,
|
||||||
|
"timed_stats": [
|
||||||
|
],
|
||||||
|
"failed_flush_operations": 0,
|
||||||
|
"account_invalid": true,
|
||||||
|
"rd_total_time_ns": 0,
|
||||||
|
"flush_operations": 0,
|
||||||
|
"wr_operations": 0,
|
||||||
|
"rd_merged": 0,
|
||||||
|
"rd_bytes": 0,
|
||||||
|
"invalid_flush_operations": 0,
|
||||||
|
"account_failed": true,
|
||||||
|
"rd_operations": 0,
|
||||||
|
"invalid_wr_operations": 0,
|
||||||
|
"invalid_rd_operations": 0
|
||||||
|
},
|
||||||
|
"node-name": "NODE_NAME"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== blockstats with -blockdev ===
|
||||||
|
|
||||||
|
Testing: -blockdev driver=null-co,node-name=null
|
||||||
|
{
|
||||||
|
QMP_VERSION
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== blockstats with -blockdev and -device ===
|
||||||
|
|
||||||
|
Testing: -blockdev driver=null-co,node-name=null -device virtio-blk,drive=null,id=virtio0
|
||||||
|
{
|
||||||
|
QMP_VERSION
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
{
|
||||||
|
"device": "",
|
||||||
|
"stats": {
|
||||||
|
"flush_total_time_ns": 0,
|
||||||
|
"wr_highest_offset": 0,
|
||||||
|
"wr_total_time_ns": 0,
|
||||||
|
"failed_wr_operations": 0,
|
||||||
|
"failed_rd_operations": 0,
|
||||||
|
"wr_merged": 0,
|
||||||
|
"wr_bytes": 0,
|
||||||
|
"timed_stats": [
|
||||||
|
],
|
||||||
|
"failed_flush_operations": 0,
|
||||||
|
"account_invalid": false,
|
||||||
|
"rd_total_time_ns": 0,
|
||||||
|
"flush_operations": 0,
|
||||||
|
"wr_operations": 0,
|
||||||
|
"rd_merged": 0,
|
||||||
|
"rd_bytes": 0,
|
||||||
|
"invalid_flush_operations": 0,
|
||||||
|
"account_failed": false,
|
||||||
|
"rd_operations": 0,
|
||||||
|
"invalid_wr_operations": 0,
|
||||||
|
"invalid_rd_operations": 0
|
||||||
|
},
|
||||||
|
"node-name": "null",
|
||||||
|
"qdev": "/machine/peripheral/virtio0/virtio-backend"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*** done
|
|
@ -224,3 +224,4 @@
|
||||||
223 rw auto quick
|
223 rw auto quick
|
||||||
225 rw auto quick
|
225 rw auto quick
|
||||||
226 auto quick
|
226 auto quick
|
||||||
|
227 auto quick
|
||||||
|
|
Loading…
Reference in New Issue