Block layer patches:
- block: Remove bdrv_read() and bdrv_write() - qemu-img: Allow rebase with no input base - blockjob: Fix coroutine thread after AioContext change - MAINTAINERS updates for pflash, curl and gluster -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJc1ZtKAAoJEH8JsnLIjy/WNaUQAL8YXgDxkxG/a7KMYzebLraV 1K9auhi2dC7kV43jUYIwj6sPrzedLzjhkTez3qFe4AJAjvrv+EorGWCv2ro4COzp 1l6i2jqilhCTV0N1MBNwG4wQY9Y4IRxGls1W0U/83FqVi38tbBPZIMsFC2pljd2W 8tRZ4KSI0BwBvGR3oeiBoOAIfPFp1lQjct7+HUpI6vcEn08+MXKDA66Y4LAG9AHR nAW9VFfUw6KBXGddFoE8WJwA1VHIJ8HUqqc4xv5cqtNO8bLYdO2FYHUf+LhI+96b nfdAL6T0isDbC0lIlC6Xue9tTFUDszEq6rNNglZ/FVHWkMtdNVyHNLLYpjC85fjH ZeUKfuEP7jEYXP415NFK0mRVZ+L6T/wlqzOz6OwKtRQsOQByonkrYcI5ejdoKC92 f/azvIRszzt8OOJal1tq0sx+vCR5gydJNnhAmyzNfspmMWsMZswbaGftx5pzGWTT eDJSdJNMqCn7lK0TtwYSVK2p3aD4SNbszbD6gzZK+hmEUpY7T8lLyN6g12b/TFMY /Vod1ltZLb2e3CmNfYqEBBHTQHBiYClad5YPZ1wM+wZMS/UDfaUlJa85zNf1jO86 JZti4hg4+IsAVNwJ2M2vsUWzl3W/4ErjpxJqGPskZ5XwpT6rOce9J1SS821eW7J5 hOMhvYGW+oVlFYL9ypKk =fcNj -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - block: Remove bdrv_read() and bdrv_write() - qemu-img: Allow rebase with no input base - blockjob: Fix coroutine thread after AioContext change - MAINTAINERS updates for pflash, curl and gluster # gpg: Signature made Fri 10 May 2019 16:39:54 BST # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: iotests: Add test for rebase without input base qemu-img: Use zero writes after source backing EOF qemu-img: Allow rebase with no input base qcow2: Remove BDRVQcow2State.cluster_sectors block: Remove bdrv_read() and bdrv_write() vvfat: Replace bdrv_{read,write}() with bdrv_{pread,pwrite}() vdi: Replace bdrv_{read,write}() with bdrv_{pread,pwrite}() qcow2: Replace bdrv_write() with bdrv_pwrite() qemu-img: Use IEC binary prefixes for size constants test-block-iothread: Job coroutine thread after AioContext switch blockjob: Fix coroutine thread after AioContext change qemu-iotests: Fix cleanup for 192 MAINTAINERS: Add an entry for the Parallel NOR Flash devices MAINTAINERS: Downgrade status of block sections without "M:" to "Odd Fixes" block: remove bs from lists before closing Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c9ba36ff2f
12
MAINTAINERS
12
MAINTAINERS
|
@ -1391,6 +1391,13 @@ F: include/hw/net/
|
|||
F: tests/virtio-net-test.c
|
||||
T: git https://github.com/jasowang/qemu.git net
|
||||
|
||||
Parallel NOR Flash devices
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
T: git https://gitlab.com/philmd/qemu.git pflash-next
|
||||
S: Maintained
|
||||
F: hw/block/pflash_cfi*.c
|
||||
F: include/hw/block/flash.h
|
||||
|
||||
SCSI
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Fam Zheng <fam@euphon.net>
|
||||
|
@ -2404,12 +2411,13 @@ F: block/ssh.c
|
|||
|
||||
CURL
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
S: Odd Fixes
|
||||
F: block/curl.c
|
||||
|
||||
GLUSTER
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
L: integration@gluster.org
|
||||
S: Odd Fixes
|
||||
F: block/gluster.c
|
||||
|
||||
Null Block Driver
|
||||
|
|
4
block.c
4
block.c
|
@ -4082,14 +4082,14 @@ static void bdrv_delete(BlockDriverState *bs)
|
|||
assert(bdrv_op_blocker_is_empty(bs));
|
||||
assert(!bs->refcnt);
|
||||
|
||||
bdrv_close(bs);
|
||||
|
||||
/* remove from list, if necessary */
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
}
|
||||
QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);
|
||||
|
||||
bdrv_close(bs);
|
||||
|
||||
g_free(bs);
|
||||
}
|
||||
|
||||
|
|
43
block/io.c
43
block/io.c
|
@ -837,42 +837,6 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
|
|||
return rwco.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a synchronous request using coroutines
|
||||
*/
|
||||
static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf,
|
||||
int nb_sectors, bool is_write, BdrvRequestFlags flags)
|
||||
{
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
|
||||
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS,
|
||||
&qiov, is_write, flags);
|
||||
}
|
||||
|
||||
/* return < 0 if error. See bdrv_write() for the return codes */
|
||||
int bdrv_read(BdrvChild *child, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
return bdrv_rw_co(child, sector_num, buf, nb_sectors, false, 0);
|
||||
}
|
||||
|
||||
/* Return < 0 if error. Important errors are:
|
||||
-EIO generic I/O error (may happen for all errors)
|
||||
-ENOMEDIUM No media inserted.
|
||||
-EINVAL Invalid sector number or nb_sectors
|
||||
-EACCES Trying to write a read-only device
|
||||
*/
|
||||
int bdrv_write(BdrvChild *child, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
return bdrv_rw_co(child, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
|
||||
}
|
||||
|
||||
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||
int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
|
@ -935,6 +899,7 @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
|||
return qiov->size;
|
||||
}
|
||||
|
||||
/* See bdrv_pwrite() for the return codes */
|
||||
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
|
||||
{
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
|
@ -958,6 +923,12 @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
|||
return qiov->size;
|
||||
}
|
||||
|
||||
/* Return no. of bytes on success or < 0 on error. Important errors are:
|
||||
-EIO generic I/O error (may happen for all errors)
|
||||
-ENOMEDIUM No media inserted.
|
||||
-EINVAL Invalid offset or number of bytes
|
||||
-EACCES Trying to write a read-only device
|
||||
*/
|
||||
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
|
||||
{
|
||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||
|
|
|
@ -2429,8 +2429,8 @@ write_refblocks:
|
|||
on_disk_refblock = (void *)((char *) *refcount_table +
|
||||
refblock_index * s->cluster_size);
|
||||
|
||||
ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
|
||||
on_disk_refblock, s->cluster_sectors);
|
||||
ret = bdrv_pwrite(bs->file, refblock_offset, on_disk_refblock,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
|
|
|
@ -1259,7 +1259,6 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
|||
|
||||
s->cluster_bits = header.cluster_bits;
|
||||
s->cluster_size = 1 << s->cluster_bits;
|
||||
s->cluster_sectors = 1 << (s->cluster_bits - BDRV_SECTOR_BITS);
|
||||
|
||||
/* Initialise version 3 header fields */
|
||||
if (header.version == 2) {
|
||||
|
|
|
@ -266,7 +266,6 @@ typedef struct Qcow2BitmapHeaderExt {
|
|||
typedef struct BDRVQcow2State {
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
int l2_slice_size;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
|
|
15
block/vdi.c
15
block/vdi.c
|
@ -171,6 +171,8 @@ typedef struct {
|
|||
uint64_t unused2[7];
|
||||
} QEMU_PACKED VdiHeader;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(VdiHeader) != 512);
|
||||
|
||||
typedef struct {
|
||||
/* The block map entries are little endian (even in memory). */
|
||||
uint32_t *bmap;
|
||||
|
@ -384,7 +386,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||
|
||||
logout("\n");
|
||||
|
||||
ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
|
||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -484,8 +486,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap,
|
||||
bmap_size);
|
||||
ret = bdrv_pread(bs->file, header.offset_bmap, s->bmap,
|
||||
bmap_size * SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
goto fail_free_bmap;
|
||||
}
|
||||
|
@ -704,7 +706,7 @@ nonallocating_write:
|
|||
assert(VDI_IS_ALLOCATED(bmap_first));
|
||||
*header = s->header;
|
||||
vdi_header_to_le(header);
|
||||
ret = bdrv_write(bs->file, 0, block, 1);
|
||||
ret = bdrv_pwrite(bs->file, 0, block, sizeof(VdiHeader));
|
||||
g_free(block);
|
||||
block = NULL;
|
||||
|
||||
|
@ -722,10 +724,11 @@ nonallocating_write:
|
|||
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
|
||||
logout("will write %u block map sectors starting from entry %u\n",
|
||||
n_sectors, bmap_first);
|
||||
ret = bdrv_write(bs->file, offset, base, n_sectors);
|
||||
ret = bdrv_pwrite(bs->file, offset * SECTOR_SIZE, base,
|
||||
n_sectors * SECTOR_SIZE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
|
||||
|
|
|
@ -1494,8 +1494,8 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
|
|||
DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
|
||||
" allocated\n", sector_num,
|
||||
n >> BDRV_SECTOR_BITS));
|
||||
if (bdrv_read(s->qcow, sector_num, buf + i * 0x200,
|
||||
n >> BDRV_SECTOR_BITS)) {
|
||||
if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE,
|
||||
buf + i * 0x200, n) < 0) {
|
||||
return -1;
|
||||
}
|
||||
i += (n >> BDRV_SECTOR_BITS) - 1;
|
||||
|
@ -1983,8 +1983,9 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
|||
if (res) {
|
||||
return -1;
|
||||
}
|
||||
res = bdrv_write(s->qcow, offset, s->cluster_buffer, 1);
|
||||
if (res) {
|
||||
res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
|
||||
s->cluster_buffer, BDRV_SECTOR_SIZE);
|
||||
if (res < 0) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
@ -3050,7 +3051,8 @@ DLOG(checkpoint());
|
|||
* Use qcow backend. Commit later.
|
||||
*/
|
||||
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
|
||||
ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
|
||||
ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, buf,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error writing to qcow backend\n");
|
||||
return ret;
|
||||
|
|
|
@ -316,10 +316,6 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
|
|||
BlockReopenQueue *queue, Error **errp);
|
||||
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
|
||||
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
|
||||
int bdrv_read(BdrvChild *child, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BdrvChild *child, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||
int bytes, BdrvRequestFlags flags);
|
||||
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
|
||||
|
|
2
job.c
2
job.c
|
@ -432,7 +432,7 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job))
|
|||
timer_del(&job->sleep_timer);
|
||||
job->busy = true;
|
||||
job_unlock();
|
||||
aio_co_wake(job->co);
|
||||
aio_co_enter(job->aio_context, job->co);
|
||||
}
|
||||
|
||||
void job_enter(Job *job)
|
||||
|
|
77
qemu-img.c
77
qemu-img.c
|
@ -37,6 +37,7 @@
|
|||
#include "qemu/option.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
@ -1216,7 +1217,7 @@ static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
|
|||
return res;
|
||||
}
|
||||
|
||||
#define IO_BUF_SIZE (2 * 1024 * 1024)
|
||||
#define IO_BUF_SIZE (2 * MiB)
|
||||
|
||||
/*
|
||||
* Check if passed sectors are empty (not allocated or contain only 0 bytes)
|
||||
|
@ -2960,7 +2961,7 @@ static int img_map(int argc, char **argv)
|
|||
int64_t n;
|
||||
|
||||
/* Probe up to 1 GiB at a time. */
|
||||
n = MIN(1 << 30, length - offset);
|
||||
n = MIN(1 * GiB, length - offset);
|
||||
ret = get_block_status(bs, offset, n, &next);
|
||||
|
||||
if (ret < 0) {
|
||||
|
@ -3311,26 +3312,30 @@ static int img_rebase(int argc, char **argv)
|
|||
char backing_name[PATH_MAX];
|
||||
QDict *options = NULL;
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
options = qdict_new();
|
||||
qdict_put_str(options, "driver", bs->backing_format);
|
||||
}
|
||||
|
||||
if (force_share) {
|
||||
if (!options) {
|
||||
if (bs->backing) {
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
options = qdict_new();
|
||||
qdict_put_str(options, "driver", bs->backing_format);
|
||||
}
|
||||
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
|
||||
}
|
||||
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
|
||||
blk_old_backing = blk_new_open(backing_name, NULL,
|
||||
options, src_flags, &local_err);
|
||||
if (!blk_old_backing) {
|
||||
error_reportf_err(local_err,
|
||||
"Could not open old backing file '%s': ",
|
||||
backing_name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
|
||||
if (force_share) {
|
||||
if (!options) {
|
||||
options = qdict_new();
|
||||
}
|
||||
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
|
||||
}
|
||||
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
|
||||
blk_old_backing = blk_new_open(backing_name, NULL,
|
||||
options, src_flags, &local_err);
|
||||
if (!blk_old_backing) {
|
||||
error_reportf_err(local_err,
|
||||
"Could not open old backing file '%s': ",
|
||||
backing_name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
blk_old_backing = NULL;
|
||||
}
|
||||
|
||||
if (out_baseimg[0]) {
|
||||
|
@ -3383,7 +3388,7 @@ static int img_rebase(int argc, char **argv)
|
|||
*/
|
||||
if (!unsafe) {
|
||||
int64_t size;
|
||||
int64_t old_backing_size;
|
||||
int64_t old_backing_size = 0;
|
||||
int64_t new_backing_size = 0;
|
||||
uint64_t offset;
|
||||
int64_t n;
|
||||
|
@ -3399,15 +3404,18 @@ static int img_rebase(int argc, char **argv)
|
|||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
old_backing_size = blk_getlength(blk_old_backing);
|
||||
if (old_backing_size < 0) {
|
||||
char backing_name[PATH_MAX];
|
||||
if (blk_old_backing) {
|
||||
old_backing_size = blk_getlength(blk_old_backing);
|
||||
if (old_backing_size < 0) {
|
||||
char backing_name[PATH_MAX];
|
||||
|
||||
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
|
||||
error_report("Could not get size of '%s': %s",
|
||||
backing_name, strerror(-old_backing_size));
|
||||
ret = -1;
|
||||
goto out;
|
||||
bdrv_get_backing_filename(bs, backing_name,
|
||||
sizeof(backing_name));
|
||||
error_report("Could not get size of '%s': %s",
|
||||
backing_name, strerror(-old_backing_size));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (blk_new_backing) {
|
||||
new_backing_size = blk_getlength(blk_new_backing);
|
||||
|
@ -3424,6 +3432,8 @@ static int img_rebase(int argc, char **argv)
|
|||
}
|
||||
|
||||
for (offset = 0; offset < size; offset += n) {
|
||||
bool buf_old_is_zero = false;
|
||||
|
||||
/* How many bytes can we handle with the next read? */
|
||||
n = MIN(IO_BUF_SIZE, size - offset);
|
||||
|
||||
|
@ -3444,6 +3454,7 @@ static int img_rebase(int argc, char **argv)
|
|||
*/
|
||||
if (offset >= old_backing_size) {
|
||||
memset(buf_old, 0, n);
|
||||
buf_old_is_zero = true;
|
||||
} else {
|
||||
if (offset + n > old_backing_size) {
|
||||
n = old_backing_size - offset;
|
||||
|
@ -3479,8 +3490,12 @@ static int img_rebase(int argc, char **argv)
|
|||
if (compare_buffers(buf_old + written, buf_new + written,
|
||||
n - written, &pnum))
|
||||
{
|
||||
ret = blk_pwrite(blk, offset + written,
|
||||
buf_old + written, pnum, 0);
|
||||
if (buf_old_is_zero) {
|
||||
ret = blk_pwrite_zeroes(blk, offset + written, pnum, 0);
|
||||
} else {
|
||||
ret = blk_pwrite(blk, offset + written,
|
||||
buf_old + written, pnum, 0);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_report("Error while writing to COW image: %s",
|
||||
strerror(-ret));
|
||||
|
|
|
@ -29,7 +29,9 @@ status=1 # failure is the default!
|
|||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
_cleanup_qemu
|
||||
_cleanup_test_img
|
||||
rm -f "$TEST_DIR/nbd"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
|
|
124
tests/qemu-iotests/252
Executable file
124
tests/qemu-iotests/252
Executable file
|
@ -0,0 +1,124 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Tests for rebasing COW images that require zero cluster support
|
||||
#
|
||||
# Copyright (C) 2019 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"
|
||||
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
rm -f "$TEST_IMG.base_new"
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
. ./common.pattern
|
||||
|
||||
# Currently only qcow2 and qed support rebasing, and only qcow2 v3 has
|
||||
# zero cluster support
|
||||
_supported_fmt qcow2
|
||||
_unsupported_imgopts 'compat=0.10'
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
CLUSTER_SIZE=65536
|
||||
|
||||
echo
|
||||
echo "=== Test rebase without input base ==="
|
||||
echo
|
||||
|
||||
# Cluster allocations to be tested:
|
||||
#
|
||||
# Backing (new) 11 -- 11 -- 11 --
|
||||
# COW image 22 22 11 11 -- --
|
||||
#
|
||||
# Expected result:
|
||||
#
|
||||
# COW image 22 22 11 11 00 --
|
||||
#
|
||||
# (Cluster 2 might be "--" after the rebase, too, but rebase just
|
||||
# compares the new backing file to the old one and disregards the
|
||||
# overlay. Therefore, it will never discard overlay clusters.)
|
||||
|
||||
_make_test_img $((6 * CLUSTER_SIZE))
|
||||
TEST_IMG="$TEST_IMG.base_new" _make_test_img $((6 * CLUSTER_SIZE))
|
||||
|
||||
echo
|
||||
|
||||
$QEMU_IO "$TEST_IMG" \
|
||||
-c "write -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
-c "write -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
| _filter_qemu_io
|
||||
|
||||
$QEMU_IO "$TEST_IMG.base_new" \
|
||||
-c "write -P 0x11 $((0 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
|
||||
-c "write -P 0x11 $((2 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
|
||||
-c "write -P 0x11 $((4 * CLUSTER_SIZE)) $CLUSTER_SIZE" \
|
||||
| _filter_qemu_io
|
||||
|
||||
echo
|
||||
|
||||
# This should be a no-op
|
||||
$QEMU_IMG rebase -b "" "$TEST_IMG"
|
||||
|
||||
# Verify the data is correct
|
||||
$QEMU_IO "$TEST_IMG" \
|
||||
-c "read -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
-c "read -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
-c "read -P 0x00 $((4 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
| _filter_qemu_io
|
||||
|
||||
echo
|
||||
|
||||
# Verify the allocation status (first four cluster should be allocated
|
||||
# in TEST_IMG, clusters 4 and 5 should be unallocated (marked as zero
|
||||
# clusters here because there is no backing file))
|
||||
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
||||
|
||||
echo
|
||||
|
||||
$QEMU_IMG rebase -b "$TEST_IMG.base_new" "$TEST_IMG"
|
||||
|
||||
# Verify the data is correct
|
||||
$QEMU_IO "$TEST_IMG" \
|
||||
-c "read -P 0x22 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
-c "read -P 0x11 $((2 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
-c "read -P 0x00 $((4 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \
|
||||
| _filter_qemu_io
|
||||
|
||||
echo
|
||||
|
||||
# Verify the allocation status (first four cluster should be allocated
|
||||
# in TEST_IMG, cluster 4 should be zero, and cluster 5 should be
|
||||
# unallocated (signified by '"depth": 1'))
|
||||
$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
39
tests/qemu-iotests/252.out
Normal file
39
tests/qemu-iotests/252.out
Normal file
|
@ -0,0 +1,39 @@
|
|||
QA output created by 252
|
||||
|
||||
=== Test rebase without input base ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=393216
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base_new', fmt=IMGFMT size=393216
|
||||
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 131072/131072 bytes at offset 131072
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 131072
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 262144
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
read 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 131072/131072 bytes at offset 131072
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 131072/131072 bytes at offset 262144
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
[{ "start": 0, "length": 262144, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
|
||||
{ "start": 262144, "length": 131072, "depth": 0, "zero": true, "data": false}]
|
||||
|
||||
read 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 131072/131072 bytes at offset 131072
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 131072/131072 bytes at offset 262144
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
[{ "start": 0, "length": 262144, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
|
||||
{ "start": 262144, "length": 65536, "depth": 0, "zero": true, "data": false},
|
||||
{ "start": 327680, "length": 65536, "depth": 1, "zero": true, "data": false}]
|
||||
*** done
|
|
@ -249,3 +249,4 @@
|
|||
247 rw auto quick
|
||||
248 rw auto quick
|
||||
249 rw auto quick
|
||||
252 rw auto backing quick
|
||||
|
|
|
@ -354,6 +354,111 @@ static void test_sync_op(const void *opaque)
|
|||
blk_unref(blk);
|
||||
}
|
||||
|
||||
typedef struct TestBlockJob {
|
||||
BlockJob common;
|
||||
bool should_complete;
|
||||
int n;
|
||||
} TestBlockJob;
|
||||
|
||||
static int test_job_prepare(Job *job)
|
||||
{
|
||||
g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn test_job_run(Job *job, Error **errp)
|
||||
{
|
||||
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
|
||||
|
||||
job_transition_to_ready(&s->common.job);
|
||||
while (!s->should_complete) {
|
||||
s->n++;
|
||||
g_assert(qemu_get_current_aio_context() == job->aio_context);
|
||||
|
||||
/* Avoid job_sleep_ns() because it marks the job as !busy. We want to
|
||||
* emulate some actual activity (probably some I/O) here so that the
|
||||
* drain involved in AioContext switches has to wait for this activity
|
||||
* to stop. */
|
||||
qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
|
||||
|
||||
job_pause_point(&s->common.job);
|
||||
}
|
||||
|
||||
g_assert(qemu_get_current_aio_context() == job->aio_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_job_complete(Job *job, Error **errp)
|
||||
{
|
||||
TestBlockJob *s = container_of(job, TestBlockJob, common.job);
|
||||
s->should_complete = true;
|
||||
}
|
||||
|
||||
BlockJobDriver test_job_driver = {
|
||||
.job_driver = {
|
||||
.instance_size = sizeof(TestBlockJob),
|
||||
.free = block_job_free,
|
||||
.user_resume = block_job_user_resume,
|
||||
.drain = block_job_drain,
|
||||
.run = test_job_run,
|
||||
.complete = test_job_complete,
|
||||
.prepare = test_job_prepare,
|
||||
},
|
||||
};
|
||||
|
||||
static void test_attach_blockjob(void)
|
||||
{
|
||||
IOThread *iothread = iothread_new();
|
||||
AioContext *ctx = iothread_get_aio_context(iothread);
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
TestBlockJob *tjob;
|
||||
|
||||
blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
|
||||
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
|
||||
blk_insert_bs(blk, bs, &error_abort);
|
||||
|
||||
tjob = block_job_create("job0", &test_job_driver, NULL, bs,
|
||||
0, BLK_PERM_ALL,
|
||||
0, 0, NULL, NULL, &error_abort);
|
||||
job_start(&tjob->common.job);
|
||||
|
||||
while (tjob->n == 0) {
|
||||
aio_poll(qemu_get_aio_context(), false);
|
||||
}
|
||||
|
||||
blk_set_aio_context(blk, ctx);
|
||||
|
||||
tjob->n = 0;
|
||||
while (tjob->n == 0) {
|
||||
aio_poll(qemu_get_aio_context(), false);
|
||||
}
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
blk_set_aio_context(blk, qemu_get_aio_context());
|
||||
aio_context_release(ctx);
|
||||
|
||||
tjob->n = 0;
|
||||
while (tjob->n == 0) {
|
||||
aio_poll(qemu_get_aio_context(), false);
|
||||
}
|
||||
|
||||
blk_set_aio_context(blk, ctx);
|
||||
|
||||
tjob->n = 0;
|
||||
while (tjob->n == 0) {
|
||||
aio_poll(qemu_get_aio_context(), false);
|
||||
}
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
job_complete_sync(&tjob->common.job, &error_abort);
|
||||
blk_set_aio_context(blk, qemu_get_aio_context());
|
||||
aio_context_release(ctx);
|
||||
|
||||
bdrv_unref(bs);
|
||||
blk_unref(blk);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
@ -368,5 +473,7 @@ int main(int argc, char **argv)
|
|||
g_test_add_data_func(t->name, t, test_sync_op);
|
||||
}
|
||||
|
||||
g_test_add_func("/attach/blockjob", test_attach_blockjob);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue