Merge remote-tracking branch 'stefanha/block' into staging

# By Kevin Wolf (7) and others
# Via Stefan Hajnoczi
* stefanha/block:
  block/raw-posix: Build fix for O_ASYNC
  vmdk: Allow space in file name
  parallels: Fix bdrv_open() error handling
  dmg: Use g_free instead of free
  dmg: Fix bdrv_open() error handling
  vpc: Fix bdrv_open() error handling
  cloop: Fix bdrv_open() error handling
  bochs: Fix bdrv_open() error handling
  sheepdog: pass vdi_id to sheep daemon for sd_close()
  vmdk: Allow selecting SCSI adapter in image creation
  block: Adds mirroring tests for resized images
  block: Fix is_allocated_above with resized files
  qemu-iotests: Add regression test for b7ab0fea
This commit is contained in:
Anthony Liguori 2013-02-01 14:40:05 -06:00
commit 77a5f4f203
15 changed files with 378 additions and 101 deletions

View File

@ -2800,7 +2800,9 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
*
* [sector_num+x, nr_sectors] allocated.
*/
if (n > pnum_inter) {
if (n > pnum_inter &&
(intermediate == top ||
sector_num + pnum_inter < intermediate->total_sectors)) {
n = pnum_inter;
}

View File

@ -114,11 +114,13 @@ static int bochs_open(BlockDriverState *bs, int flags)
int i;
struct bochs_header bochs;
struct bochs_header_v1 header_v1;
int ret;
bs->read_only = 1; // no write support yet
if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) {
goto fail;
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
if (ret < 0) {
return ret;
}
if (strcmp(bochs.magic, HEADER_MAGIC) ||
@ -138,9 +140,13 @@ static int bochs_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4) != s->catalog_size * 4)
goto fail;
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
@ -153,8 +159,10 @@ static int bochs_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
fail:
return -1;
fail:
g_free(s->catalog_bitmap);
return ret;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@ -57,27 +57,32 @@ static int cloop_open(BlockDriverState *bs, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size, max_compressed_block_size = 1, i;
int ret;
bs->read_only = 1;
/* read header */
if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
if (ret < 0) {
return ret;
}
s->block_size = be32_to_cpu(s->block_size);
if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
if (ret < 0) {
return ret;
}
s->n_blocks = be32_to_cpu(s->n_blocks);
/* read offsets */
offsets_size = s->n_blocks * sizeof(uint64_t);
s->offsets = g_malloc(offsets_size);
if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) <
offsets_size) {
goto cloop_close;
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
if (ret < 0) {
goto fail;
}
for(i=0;i<s->n_blocks;i++) {
s->offsets[i] = be64_to_cpu(s->offsets[i]);
if (i > 0) {
@ -92,7 +97,8 @@ static int cloop_open(BlockDriverState *bs, int flags)
s->compressed_block = g_malloc(max_compressed_block_size + 1);
s->uncompressed_block = g_malloc(s->block_size);
if (inflateInit(&s->zstream) != Z_OK) {
goto cloop_close;
ret = -EINVAL;
goto fail;
}
s->current_block = s->n_blocks;
@ -101,8 +107,11 @@ static int cloop_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
return 0;
cloop_close:
return -1;
fail:
g_free(s->offsets);
g_free(s->compressed_block);
g_free(s->uncompressed_block);
return ret;
}
static inline int cloop_read_block(BlockDriverState *bs, int block_num)

View File

@ -57,29 +57,42 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static off_t read_off(BlockDriverState *bs, int64_t offset)
static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
{
uint64_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 8) < 8)
return 0;
return be64_to_cpu(buffer);
uint64_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 8);
if (ret < 0) {
return ret;
}
*result = be64_to_cpu(buffer);
return 0;
}
static off_t read_uint32(BlockDriverState *bs, int64_t offset)
static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
{
uint32_t buffer;
if (bdrv_pread(bs->file, offset, &buffer, 4) < 4)
return 0;
return be32_to_cpu(buffer);
uint32_t buffer;
int ret;
ret = bdrv_pread(bs->file, offset, &buffer, 4);
if (ret < 0) {
return ret;
}
*result = be32_to_cpu(buffer);
return 0;
}
static int dmg_open(BlockDriverState *bs, int flags)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count, tmp;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
int64_t offset;
int ret;
bs->read_only = 1;
s->n_chunks = 0;
@ -88,21 +101,32 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* read offset of info blocks */
offset = bdrv_getlength(bs->file);
if (offset < 0) {
ret = offset;
goto fail;
}
offset -= 0x1d8;
info_begin = read_off(bs, offset);
if (info_begin == 0) {
goto fail;
}
if (read_uint32(bs, info_begin) != 0x100) {
ret = read_uint64(bs, offset, &info_begin);
if (ret < 0) {
goto fail;
} else if (info_begin == 0) {
ret = -EINVAL;
goto fail;
}
count = read_uint32(bs, info_begin + 4);
if (count == 0) {
ret = read_uint32(bs, info_begin, &tmp);
if (ret < 0) {
goto fail;
} else if (tmp != 0x100) {
ret = -EINVAL;
goto fail;
}
ret = read_uint32(bs, info_begin + 4, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
goto fail;
}
info_end = info_begin + count;
@ -114,12 +138,20 @@ static int dmg_open(BlockDriverState *bs, int flags)
while (offset < info_end) {
uint32_t type;
count = read_uint32(bs, offset);
if(count==0)
goto fail;
ret = read_uint32(bs, offset, &count);
if (ret < 0) {
goto fail;
} else if (count == 0) {
ret = -EINVAL;
goto fail;
}
offset += 4;
type = read_uint32(bs, offset);
ret = read_uint32(bs, offset, &type);
if (ret < 0) {
goto fail;
}
if (type == 0x6d697368 && count >= 244) {
int new_size, chunk_count;
@ -134,8 +166,11 @@ static int dmg_open(BlockDriverState *bs, int flags)
s->sectors = g_realloc(s->sectors, new_size);
s->sectorcounts = g_realloc(s->sectorcounts, new_size);
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
s->types[i] = read_uint32(bs, offset);
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
ret = read_uint32(bs, offset, &s->types[i]);
if (ret < 0) {
goto fail;
}
offset += 4;
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
if(s->types[i]==0xffffffff) {
@ -149,17 +184,31 @@ static int dmg_open(BlockDriverState *bs, int flags)
}
offset += 4;
s->sectors[i] = last_out_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->sectors[i]);
if (ret < 0) {
goto fail;
}
s->sectors[i] += last_out_offset;
offset += 8;
s->sectorcounts[i] = read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->sectorcounts[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
s->offsets[i] = last_in_offset+read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->offsets[i]);
if (ret < 0) {
goto fail;
}
s->offsets[i] += last_in_offset;
offset += 8;
s->lengths[i] = read_off(bs, offset);
offset += 8;
ret = read_uint64(bs, offset, &s->lengths[i]);
if (ret < 0) {
goto fail;
}
offset += 8;
if(s->lengths[i]>max_compressed_size)
max_compressed_size = s->lengths[i];
@ -173,15 +222,25 @@ static int dmg_open(BlockDriverState *bs, int flags)
/* initialize zlib engine */
s->compressed_chunk = g_malloc(max_compressed_size+1);
s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
if(inflateInit(&s->zstream) != Z_OK)
goto fail;
if(inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
}
s->current_chunk = s->n_chunks;
qemu_co_mutex_init(&s->lock);
return 0;
fail:
return -1;
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
return ret;
}
static inline int is_sector_in_chunk(BDRVDMGState* s,
@ -296,15 +355,15 @@ static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,
static void dmg_close(BlockDriverState *bs)
{
BDRVDMGState *s = bs->opaque;
if(s->n_chunks>0) {
free(s->types);
free(s->offsets);
free(s->lengths);
free(s->sectors);
free(s->sectorcounts);
}
free(s->compressed_chunk);
free(s->uncompressed_chunk);
g_free(s->types);
g_free(s->offsets);
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
g_free(s->compressed_chunk);
g_free(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}

View File

@ -73,14 +73,18 @@ static int parallels_open(BlockDriverState *bs, int flags)
BDRVParallelsState *s = bs->opaque;
int i;
struct parallels_header ph;
int ret;
bs->read_only = 1; // no write support yet
if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph))
ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
if (ret < 0) {
goto fail;
}
if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
(le32_to_cpu(ph.version) != HEADER_VERSION)) {
ret = -EMEDIUMTYPE;
goto fail;
}
@ -90,18 +94,21 @@ static int parallels_open(BlockDriverState *bs, int flags)
s->catalog_size = le32_to_cpu(ph.catalog_entries);
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) !=
s->catalog_size * 4)
goto fail;
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->catalog_size; i++)
le32_to_cpus(&s->catalog_bitmap[i]);
qemu_co_mutex_init(&s->lock);
return 0;
fail:
if (s->catalog_bitmap)
g_free(s->catalog_bitmap);
return -1;
g_free(s->catalog_bitmap);
return ret;
}
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)

View File

@ -345,11 +345,20 @@ static int raw_reopen_prepare(BDRVReopenState *state,
raw_s->fd = -1;
int fcntl_flags = O_APPEND | O_ASYNC | O_NONBLOCK;
int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME
fcntl_flags |= O_NOATIME;
#endif
#ifdef O_ASYNC
/* Not all operating systems have O_ASYNC, and those that don't
* will not let us track the state into raw_s->open_flags (typically
* you achieve the same effect with an ioctl, for example I_SETSIG
* on Solaris). But we do not use O_ASYNC, so that's fine.
*/
assert((s->open_flags & O_ASYNC) == 0);
#endif
if ((raw_s->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
/* dup the original fd */
/* TODO: use qemu fcntl wrapper */

View File

@ -145,7 +145,7 @@ typedef struct SheepdogVdiReq {
uint32_t id;
uint32_t data_length;
uint64_t vdi_size;
uint32_t base_vdi_id;
uint32_t vdi_id;
uint32_t copies;
uint32_t snapid;
uint32_t pad[3];
@ -1201,7 +1201,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_NEW_VDI;
hdr.base_vdi_id = base_vid;
hdr.vdi_id = base_vid;
wlen = SD_MAX_VDI_LEN;
@ -1384,6 +1384,7 @@ static void sd_close(BlockDriverState *bs)
memset(&hdr, 0, sizeof(hdr));
hdr.opcode = SD_OP_RELEASE_VDI;
hdr.vdi_id = s->inode.vdi_id;
wlen = strlen(s->name) + 1;
hdr.data_length = wlen;
hdr.flags = SD_FLAG_CMD_WRITE;

View File

@ -641,7 +641,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
* RW [size in sectors] SPARSE "file-name.vmdk"
*/
flat_offset = -1;
ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64,
access, &sectors, type, fname, &flat_offset);
if (ret < 4 || strcmp(access, "RW")) {
goto next_line;
@ -653,14 +653,6 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
return -EINVAL;
}
/* trim the quotation marks around */
if (fname[0] == '"') {
memmove(fname, fname + 1, strlen(fname));
if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
return -EINVAL;
}
fname[strlen(fname) - 1] = '\0';
}
if (sectors <= 0 ||
(strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
(strcmp(access, "RW"))) {
@ -1442,6 +1434,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
int fd, idx = 0;
char desc[BUF_SIZE];
int64_t total_size = 0, filesize;
const char *adapter_type = NULL;
const char *backing_file = NULL;
const char *fmt = NULL;
int flags = 0;
@ -1453,6 +1446,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
const char *desc_extent_line;
char parent_desc_line[BUF_SIZE] = "";
uint32_t parent_cid = 0xffffffff;
uint32_t number_heads = 16;
const char desc_template[] =
"# Disk DescriptorFile\n"
"version=1\n"
@ -1469,9 +1463,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
"\n"
"ddb.virtualHWVersion = \"%d\"\n"
"ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.heads = \"%d\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
"ddb.adapterType = \"%s\"\n";
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
return -EINVAL;
@ -1480,6 +1474,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n;
} else if (!strcmp(options->name, BLOCK_OPT_ADAPTER_TYPE)) {
adapter_type = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
@ -1489,6 +1485,20 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
}
options++;
}
if (!adapter_type) {
adapter_type = "ide";
} else if (strcmp(adapter_type, "ide") &&
strcmp(adapter_type, "buslogic") &&
strcmp(adapter_type, "lsilogic") &&
strcmp(adapter_type, "legacyESX")) {
fprintf(stderr, "VMDK: Unknown adapter type: '%s'.\n", adapter_type);
return -EINVAL;
}
if (strcmp(adapter_type, "ide") != 0) {
/* that's the number of heads with which vmware operates when
creating, exporting, etc. vmdk files with a non-ide adapter type */
number_heads = 255;
}
if (!fmt) {
/* Default format to monolithicSparse */
fmt = "monolithicSparse";
@ -1576,7 +1586,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
parent_desc_line,
ext_desc_lines,
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
total_size / (int64_t)(63 * 16 * 512));
total_size / (int64_t)(63 * number_heads * 512), number_heads,
adapter_type);
if (split || flat) {
fd = qemu_open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
@ -1660,6 +1671,12 @@ static QEMUOptionParameter vmdk_create_options[] = {
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{
.name = BLOCK_OPT_ADAPTER_TYPE,
.type = OPT_STRING,
.help = "Virtual adapter type, can be one of "
"ide (default), lsilogic, buslogic or legacyESX"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,

View File

@ -163,24 +163,33 @@ static int vpc_open(BlockDriverState *bs, int flags)
struct vhd_dyndisk_header* dyndisk_header;
uint8_t buf[HEADER_SIZE];
uint32_t checksum;
int err = -1;
int disk_type = VHD_DYNAMIC;
int ret;
if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
if (ret < 0) {
goto fail;
}
footer = (struct vhd_footer*) s->footer_buf;
if (strncmp(footer->creator, "conectix", 8)) {
int64_t offset = bdrv_getlength(bs->file);
if (offset < HEADER_SIZE) {
if (offset < 0) {
ret = offset;
goto fail;
} else if (offset < HEADER_SIZE) {
ret = -EINVAL;
goto fail;
}
/* If a fixed disk, the footer is found only at the end of the file */
if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE)
!= HEADER_SIZE) {
ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
HEADER_SIZE);
if (ret < 0) {
goto fail;
}
if (strncmp(footer->creator, "conectix", 8)) {
ret = -EMEDIUMTYPE;
goto fail;
}
disk_type = VHD_FIXED;
@ -203,19 +212,21 @@ static int vpc_open(BlockDriverState *bs, int flags)
/* Allow a maximum disk size of approximately 2 TB */
if (bs->total_sectors >= 65535LL * 255 * 255) {
err = -EFBIG;
ret = -EFBIG;
goto fail;
}
if (disk_type == VHD_DYNAMIC) {
if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE) != HEADER_SIZE) {
ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
HEADER_SIZE);
if (ret < 0) {
goto fail;
}
dyndisk_header = (struct vhd_dyndisk_header *) buf;
if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
ret = -EINVAL;
goto fail;
}
@ -226,8 +237,10 @@ static int vpc_open(BlockDriverState *bs, int flags)
s->pagetable = g_malloc(s->max_table_entries * 4);
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4) != s->max_table_entries * 4) {
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
s->max_table_entries * 4);
if (ret < 0) {
goto fail;
}
@ -265,8 +278,13 @@ static int vpc_open(BlockDriverState *bs, int flags)
migrate_add_blocker(s->migration_blocker);
return 0;
fail:
return err;
fail:
g_free(s->pagetable);
#ifdef CACHE
g_free(s->pageentry_u8);
#endif
return ret;
}
static int vpc_reopen_prepare(BDRVReopenState *state,

View File

@ -56,6 +56,7 @@
#define BLOCK_OPT_SUBFMT "subformat"
#define BLOCK_OPT_COMPAT_LEVEL "compat"
#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts"
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
typedef struct BdrvTrackedRequest BdrvTrackedRequest;

View File

@ -344,6 +344,54 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
self.assertTrue(self.compare_images(test_img, target_img),
'target image does not match source after mirroring')
class TestMirrorResized(ImageMirroringTestCase):
backing_len = 1 * 1024 * 1024 # MB
image_len = 2 * 1024 * 1024 # MB
def setUp(self):
self.create_image(backing_img, TestMirrorResized.backing_len)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
qemu_img('resize', test_img, '2M')
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
def tearDown(self):
self.vm.shutdown()
os.remove(test_img)
os.remove(backing_img)
try:
os.remove(target_img)
except OSError:
pass
def test_complete_top(self):
self.assert_no_active_mirrors()
result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
target=target_img)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
self.vm.shutdown()
self.assertTrue(self.compare_images(test_img, target_img),
'target image does not match source after mirroring')
def test_complete_full(self):
self.assert_no_active_mirrors()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
self.assert_qmp(result, 'return', {})
self.complete_and_wait()
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
self.vm.shutdown()
self.assertTrue(self.compare_images(test_img, target_img),
'target image does not match source after mirroring')
class TestReadErrors(ImageMirroringTestCase):
image_len = 2 * 1024 * 1024 # MB

View File

@ -1,5 +1,5 @@
......................
........................
----------------------------------------------------------------------
Ran 22 tests
Ran 24 tests
OK

75
tests/qemu-iotests/047 Executable file
View File

@ -0,0 +1,75 @@
#!/bin/bash
#
# Regression test for commit b7ab0fea (which was a corruption fix,
# despite the commit message claiming otherwise)
#
# Copyright (C) 2013 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`
tmp=/tmp/$$
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 qcow2
_supported_proto generic
_supported_os Linux
size=128M
_make_test_img $size
function qemu_io_cmds()
{
cat <<EOF
write -P 0x66 0 320k
write 320k 128k
write -P 0x55 1M 128k
write -P 0x88 448k 128k
discard 320k 128k
aio_flush
write -P 0x77 0 480k
aio_flush
read -P 0x77 0 480k
read -P 0x88 480k 96k
read -P 0x55 1M 128k
EOF
}
qemu_io_cmds | $QEMU_IO $TEST_IMG | _filter_qemu_io
_check_test_img
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@ -0,0 +1,22 @@
QA output created by 047
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
qemu-io> wrote 327680/327680 bytes at offset 0
320 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> wrote 131072/131072 bytes at offset 327680
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> wrote 131072/131072 bytes at offset 1048576
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> wrote 131072/131072 bytes at offset 458752
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> discard 131072/131072 bytes at offset 327680
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> qemu-io> qemu-io> wrote 491520/491520 bytes at offset 0
480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> qemu-io> qemu-io> read 491520/491520 bytes at offset 0
480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> read 98304/98304 bytes at offset 491520
96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> read 131072/131072 bytes at offset 1048576
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> No errors were found on the image.
*** done

View File

@ -53,3 +53,4 @@
044 rw auto
045 rw auto
046 rw auto aio
047 rw auto