Compare commits
112 Commits
pull-input
...
pull-gtk-5
Author | SHA1 | Date | |
---|---|---|---|
|
800b0e814b | ||
|
55519a4b24 | ||
|
f85e3457ce | ||
|
9c269f6d7b | ||
|
dffacd4654 | ||
|
20c50a955f | ||
|
bd7ce902ab | ||
|
e20c016e32 | ||
|
dc491cfc14 | ||
|
25eccc37ff | ||
|
ecce1929bc | ||
|
e61031cdd8 | ||
|
0d0e044dee | ||
|
466e6e9d13 | ||
|
8ae60ee85c | ||
|
54bee5c2b4 | ||
|
8c2664d869 | ||
|
4d1cb6e6f5 | ||
|
f187743acd | ||
|
b998875dcf | ||
|
bae2c27090 | ||
|
cd7ccc8351 | ||
|
d097696eba | ||
|
3b418d0c45 | ||
|
cd40890816 | ||
|
e3fa4bfa72 | ||
|
8885eadedd | ||
|
4c2e5f8f46 | ||
|
cbee81f6de | ||
|
5913815a17 | ||
|
888157fe96 | ||
|
de03c3164a | ||
|
87d8354de3 | ||
|
784a5592c9 | ||
|
97891afab8 | ||
|
c97ca29db0 | ||
|
b2f9c08a4f | ||
|
27898a5daa | ||
|
d581eb7ca4 | ||
|
82c6f51373 | ||
|
9bcec938aa | ||
|
53e11bd384 | ||
|
507979a8bd | ||
|
c792707f54 | ||
|
9302e863aa | ||
|
afbcc40bee | ||
|
5dae6e30c5 | ||
|
6a83f8b5be | ||
|
c05e4667be | ||
|
11b128f406 | ||
|
6b7d4c5558 | ||
|
8f4754ede5 | ||
|
1e7226f70c | ||
|
f0dce23475 | ||
|
686d7148ec | ||
|
c165f77580 | ||
|
eb71803b04 | ||
|
b404bf8542 | ||
|
73ed27ec28 | ||
|
2c1885adcf | ||
|
cab60de930 | ||
|
0abe740f1d | ||
|
bb572aefbd | ||
|
2b5d5953ee | ||
|
db8a31d11d | ||
|
b106ad9185 | ||
|
6d33e8e7dc | ||
|
2d51c32c4b | ||
|
ce48f2f441 | ||
|
8c7de28305 | ||
|
5dab2faddc | ||
|
a1b3955c94 | ||
|
24342f2cae | ||
|
6d4b9e55fc | ||
|
1d7678dec4 | ||
|
63fa06dc97 | ||
|
5e71dfad76 | ||
|
97f1c45c6f | ||
|
a9ba36a45d | ||
|
8e53abbc20 | ||
|
e3737b820b | ||
|
246f65838d | ||
|
3dd8a6763b | ||
|
24f3078a04 | ||
|
42d43d35d9 | ||
|
f56b9bc3ae | ||
|
7b103b36d6 | ||
|
509a41bab5 | ||
|
d65f97a82c | ||
|
05560fcebb | ||
|
47f73da0a7 | ||
|
c5a33ee9ee | ||
|
4c7096607d | ||
|
bdf866fe6c | ||
|
d25295d4ef | ||
|
95224e87a7 | ||
|
7373fc7693 | ||
|
a4ec5bb718 | ||
|
cebac61498 | ||
|
efdf6a56a7 | ||
|
e683eb9ecc | ||
|
627b1a17ce | ||
|
66e0c7b187 | ||
|
abc53733f3 | ||
|
2d888c099c | ||
|
fc9677915c | ||
|
592408b8ca | ||
|
5c4e24c151 | ||
|
d597a32a6d | ||
|
0875709429 | ||
|
d766825190 | ||
|
96b8ca47f8 |
15
MAINTAINERS
15
MAINTAINERS
@@ -304,7 +304,7 @@ S: Maintained
|
||||
F: hw/*/versatile*
|
||||
|
||||
Xilinx Zynq
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/arm/xilinx_zynq.c
|
||||
F: hw/misc/zynq_slcr.c
|
||||
@@ -353,7 +353,7 @@ S: Maintained
|
||||
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
|
||||
|
||||
petalogix_ml605
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/microblaze/petalogix_ml605_mmu.c
|
||||
|
||||
@@ -592,7 +592,7 @@ S: Orphan
|
||||
F: hw/scsi/lsi53c895a.c
|
||||
|
||||
SSI
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/ssi/*
|
||||
F: hw/block/m25p80.c
|
||||
@@ -623,6 +623,7 @@ M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||
S: Supported
|
||||
F: hw/9pfs/
|
||||
F: fsdev/
|
||||
F: tests/virtio-9p-test.c
|
||||
T: git git://github.com/kvaneesh/QEMU.git
|
||||
|
||||
virtio-blk
|
||||
@@ -648,9 +649,10 @@ nvme
|
||||
M: Keith Busch <keith.busch@intel.com>
|
||||
S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
Xilinx EDK
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/*/xilinx_*
|
||||
@@ -694,7 +696,7 @@ F: include/hw/cpu/icc_bus.h
|
||||
F: hw/cpu/icc_bus.c
|
||||
|
||||
Device Tree
|
||||
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: device_tree.[ch]
|
||||
@@ -715,7 +717,8 @@ F: hw/display/qxl*
|
||||
|
||||
Graphics
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
S: Maintained
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: ui/
|
||||
|
||||
Cocoa graphics
|
||||
|
2
Makefile
2
Makefile
@@ -376,7 +376,7 @@ endif
|
||||
ifneq ($(CONFIG_MODULES),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$${s//\//-}"; \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(HELPERS-y),)
|
||||
|
165
block.c
165
block.c
@@ -767,6 +767,11 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||
{
|
||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||
|
||||
/* The backing file of a temporary snapshot is read-only */
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
open_flags &= ~BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear flags that are internal to the block layer before opening the
|
||||
* image.
|
||||
@@ -968,7 +973,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
||||
{
|
||||
BlockDriver *drv;
|
||||
const char *drvname;
|
||||
bool allow_protocol_prefix = false;
|
||||
bool parse_filename = false;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -977,7 +982,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
||||
filename = qdict_get_try_str(*options, "filename");
|
||||
} else if (filename && !qdict_haskey(*options, "filename")) {
|
||||
qdict_put(*options, "filename", qstring_from_str(filename));
|
||||
allow_protocol_prefix = true;
|
||||
parse_filename = true;
|
||||
} else {
|
||||
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
|
||||
"same time");
|
||||
@@ -994,7 +999,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
||||
}
|
||||
qdict_del(*options, "driver");
|
||||
} else if (filename) {
|
||||
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
|
||||
drv = bdrv_find_protocol(filename, parse_filename);
|
||||
if (!drv) {
|
||||
error_setg(errp, "Unknown protocol");
|
||||
}
|
||||
@@ -1010,7 +1015,7 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
||||
}
|
||||
|
||||
/* Parse the filename and open it */
|
||||
if (drv->bdrv_parse_filename && filename) {
|
||||
if (drv->bdrv_parse_filename && parse_filename) {
|
||||
drv->bdrv_parse_filename(filename, *options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
@@ -1162,6 +1167,73 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||
char tmp_filename[PATH_MAX + 1];
|
||||
|
||||
int64_t total_size;
|
||||
BlockDriver *bdrv_qcow2;
|
||||
QEMUOptionParameter *create_options;
|
||||
QDict *snapshot_options;
|
||||
BlockDriverState *bs_snapshot;
|
||||
Error *local_err;
|
||||
int ret;
|
||||
|
||||
/* if snapshot, we create a temporary backing file and open it
|
||||
instead of opening 'filename' directly */
|
||||
|
||||
/* Get the required size from the image */
|
||||
total_size = bdrv_getlength(bs);
|
||||
if (total_size < 0) {
|
||||
error_setg_errno(errp, -total_size, "Could not get image size");
|
||||
return;
|
||||
}
|
||||
total_size &= BDRV_SECTOR_MASK;
|
||||
|
||||
/* Create the temporary image */
|
||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
||||
NULL);
|
||||
|
||||
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
||||
|
||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
||||
free_option_parameters(create_options);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||
"'%s': %s", tmp_filename,
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare a new options QDict for the temporary file */
|
||||
snapshot_options = qdict_new();
|
||||
qdict_put(snapshot_options, "file.driver",
|
||||
qstring_from_str("file"));
|
||||
qdict_put(snapshot_options, "file.filename",
|
||||
qstring_from_str(tmp_filename));
|
||||
|
||||
bs_snapshot = bdrv_new("");
|
||||
bs_snapshot->is_temporary = 1;
|
||||
|
||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||
bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_append(bs_snapshot, bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||
*
|
||||
@@ -1182,8 +1254,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
BlockDriver *drv, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||
char tmp_filename[PATH_MAX + 1];
|
||||
BlockDriverState *file = NULL, *bs;
|
||||
const char *drvname;
|
||||
Error *local_err = NULL;
|
||||
@@ -1243,74 +1313,6 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
}
|
||||
}
|
||||
|
||||
/* For snapshot=on, create a temporary qcow2 overlay */
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
BlockDriverState *bs1;
|
||||
int64_t total_size;
|
||||
BlockDriver *bdrv_qcow2;
|
||||
QEMUOptionParameter *create_options;
|
||||
QDict *snapshot_options;
|
||||
|
||||
/* if snapshot, we create a temporary backing file and open it
|
||||
instead of opening 'filename' directly */
|
||||
|
||||
/* Get the required size from the image */
|
||||
QINCREF(options);
|
||||
bs1 = NULL;
|
||||
ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING,
|
||||
drv, &local_err);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
|
||||
|
||||
bdrv_unref(bs1);
|
||||
|
||||
/* Create the temporary image */
|
||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not get temporary filename");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bdrv_qcow2 = bdrv_find_format("qcow2");
|
||||
create_options = parse_option_parameters("", bdrv_qcow2->create_options,
|
||||
NULL);
|
||||
|
||||
set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
|
||||
|
||||
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
|
||||
free_option_parameters(create_options);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not create temporary overlay "
|
||||
"'%s': %s", tmp_filename,
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Prepare a new options QDict for the temporary file, where user
|
||||
* options refer to the backing file */
|
||||
if (filename) {
|
||||
qdict_put(options, "file.filename", qstring_from_str(filename));
|
||||
}
|
||||
if (drv) {
|
||||
qdict_put(options, "driver", qstring_from_str(drv->format_name));
|
||||
}
|
||||
|
||||
snapshot_options = qdict_new();
|
||||
qdict_put(snapshot_options, "backing", options);
|
||||
qdict_flatten(snapshot_options);
|
||||
|
||||
bs->options = snapshot_options;
|
||||
options = qdict_clone_shallow(bs->options);
|
||||
|
||||
filename = tmp_filename;
|
||||
drv = bdrv_qcow2;
|
||||
bs->is_temporary = 1;
|
||||
}
|
||||
|
||||
/* Open image file without format layer */
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
flags |= BDRV_O_ALLOW_RDWR;
|
||||
@@ -1372,6 +1374,17 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
}
|
||||
}
|
||||
|
||||
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
||||
* temporary snapshot afterwards. */
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
bdrv_append_temp_snapshot(bs, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto close_and_fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
/* Check if any unknown options were used */
|
||||
if (options && (qdict_size(options) != 0)) {
|
||||
@@ -2588,6 +2601,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
|
103
block/bochs.c
103
block/bochs.c
@@ -38,57 +38,42 @@
|
||||
|
||||
// not allocated: 0xffffffff
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header_v1 {
|
||||
char magic[32]; // "Bochs Virtual HD Image"
|
||||
char type[16]; // "Redolog"
|
||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
||||
uint32_t version;
|
||||
uint32_t header; // size of header
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t catalog; // num of entries
|
||||
uint32_t bitmap; // bitmap size
|
||||
uint32_t extent; // extent size
|
||||
uint64_t disk; // disk size
|
||||
char padding[HEADER_SIZE - 64 - 8 - 20];
|
||||
} redolog;
|
||||
char padding[HEADER_SIZE - 64 - 8];
|
||||
} extra;
|
||||
};
|
||||
|
||||
// always little-endian
|
||||
struct bochs_header {
|
||||
char magic[32]; // "Bochs Virtual HD Image"
|
||||
char type[16]; // "Redolog"
|
||||
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
||||
char magic[32]; /* "Bochs Virtual HD Image" */
|
||||
char type[16]; /* "Redolog" */
|
||||
char subtype[16]; /* "Undoable" / "Volatile" / "Growing" */
|
||||
uint32_t version;
|
||||
uint32_t header; // size of header
|
||||
uint32_t header; /* size of header */
|
||||
|
||||
uint32_t catalog; /* num of entries */
|
||||
uint32_t bitmap; /* bitmap size */
|
||||
uint32_t extent; /* extent size */
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t catalog; // num of entries
|
||||
uint32_t bitmap; // bitmap size
|
||||
uint32_t extent; // extent size
|
||||
uint32_t reserved; // for ???
|
||||
uint64_t disk; // disk size
|
||||
char padding[HEADER_SIZE - 64 - 8 - 24];
|
||||
} redolog;
|
||||
char padding[HEADER_SIZE - 64 - 8];
|
||||
uint32_t reserved; /* for ??? */
|
||||
uint64_t disk; /* disk size */
|
||||
char padding[HEADER_SIZE - 64 - 20 - 12];
|
||||
} QEMU_PACKED redolog;
|
||||
struct {
|
||||
uint64_t disk; /* disk size */
|
||||
char padding[HEADER_SIZE - 64 - 20 - 8];
|
||||
} QEMU_PACKED redolog_v1;
|
||||
char padding[HEADER_SIZE - 64 - 20];
|
||||
} extra;
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct BDRVBochsState {
|
||||
CoMutex lock;
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
uint32_t catalog_size;
|
||||
|
||||
int data_offset;
|
||||
uint32_t data_offset;
|
||||
|
||||
int bitmap_blocks;
|
||||
int extent_blocks;
|
||||
int extent_size;
|
||||
uint32_t bitmap_blocks;
|
||||
uint32_t extent_blocks;
|
||||
uint32_t extent_size;
|
||||
} BDRVBochsState;
|
||||
|
||||
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
@@ -112,9 +97,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int i;
|
||||
uint32_t i;
|
||||
struct bochs_header bochs;
|
||||
struct bochs_header_v1 header_v1;
|
||||
int ret;
|
||||
|
||||
bs->read_only = 1; // no write support yet
|
||||
@@ -134,13 +118,19 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||
memcpy(&header_v1, &bochs, sizeof(bochs));
|
||||
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog_v1.disk) / 512;
|
||||
} else {
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
}
|
||||
|
||||
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
||||
/* Limit to 1M entries to avoid unbounded allocation. This is what is
|
||||
* needed for the largest image that bximage can create (~8 TB). */
|
||||
s->catalog_size = le32_to_cpu(bochs.catalog);
|
||||
if (s->catalog_size > 0x100000) {
|
||||
error_setg(errp, "Catalog size is too large");
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||
|
||||
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||
@@ -154,10 +144,24 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
||||
|
||||
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
|
||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
|
||||
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.bitmap) - 1) / 512;
|
||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||
|
||||
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
|
||||
s->extent_size = le32_to_cpu(bochs.extent);
|
||||
if (s->extent_size == 0) {
|
||||
error_setg(errp, "Extent size may not be zero");
|
||||
return -EINVAL;
|
||||
} else if (s->extent_size > 0x800000) {
|
||||
error_setg(errp, "Extent size %" PRIu32 " is too large",
|
||||
s->extent_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s->catalog_size < bs->total_sectors / s->extent_size) {
|
||||
error_setg(errp, "Catalog size is too small for this disk size");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
return 0;
|
||||
@@ -170,8 +174,8 @@ fail:
|
||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int64_t offset = sector_num * 512;
|
||||
int64_t extent_index, extent_offset, bitmap_offset;
|
||||
uint64_t offset = sector_num * 512;
|
||||
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||
char bitmap_entry;
|
||||
|
||||
// seek to sector
|
||||
@@ -182,7 +186,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
return -1; /* not allocated */
|
||||
}
|
||||
|
||||
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
||||
bitmap_offset = s->data_offset +
|
||||
(512 * (uint64_t) s->catalog_bitmap[extent_index] *
|
||||
(s->extent_blocks + s->bitmap_blocks));
|
||||
|
||||
/* read in bitmap for current extent */
|
||||
|
@@ -26,6 +26,9 @@
|
||||
#include "qemu/module.h"
|
||||
#include <zlib.h>
|
||||
|
||||
/* Maximum compressed block size */
|
||||
#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
||||
|
||||
typedef struct BDRVCloopState {
|
||||
CoMutex lock;
|
||||
uint32_t block_size;
|
||||
@@ -68,6 +71,26 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
s->block_size = be32_to_cpu(s->block_size);
|
||||
if (s->block_size % 512) {
|
||||
error_setg(errp, "block_size %u must be a multiple of 512",
|
||||
s->block_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->block_size == 0) {
|
||||
error_setg(errp, "block_size cannot be zero");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but
|
||||
* we can accept more. Prevent ridiculous values like 4 GB - 1 since we
|
||||
* need a buffer this big.
|
||||
*/
|
||||
if (s->block_size > MAX_BLOCK_SIZE) {
|
||||
error_setg(errp, "block_size %u must be %u MB or less",
|
||||
s->block_size,
|
||||
MAX_BLOCK_SIZE / (1024 * 1024));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||
if (ret < 0) {
|
||||
@@ -76,7 +99,23 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||
|
||||
/* read offsets */
|
||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||
/* Prevent integer overflow */
|
||||
error_setg(errp, "n_blocks %u must be %zu or less",
|
||||
s->n_blocks,
|
||||
(UINT32_MAX - 1) / sizeof(uint64_t));
|
||||
return -EINVAL;
|
||||
}
|
||||
offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
||||
if (offsets_size > 512 * 1024 * 1024) {
|
||||
/* Prevent ridiculous offsets_size which causes memory allocation to
|
||||
* fail or overflows bdrv_pread() size. In practice the 512 MB
|
||||
* offsets[] limit supports 16 TB images at 256 KB block size.
|
||||
*/
|
||||
error_setg(errp, "image requires too many offsets, "
|
||||
"try increasing block size");
|
||||
return -EINVAL;
|
||||
}
|
||||
s->offsets = g_malloc(offsets_size);
|
||||
|
||||
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
||||
@@ -84,15 +123,39 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for(i=0;i<s->n_blocks;i++) {
|
||||
for (i = 0; i < s->n_blocks + 1; i++) {
|
||||
uint64_t size;
|
||||
|
||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||
if (i > 0) {
|
||||
uint32_t size = s->offsets[i] - s->offsets[i - 1];
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->offsets[i] < s->offsets[i - 1]) {
|
||||
error_setg(errp, "offsets not monotonically increasing at "
|
||||
"index %u, image file is corrupt", i);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size = s->offsets[i] - s->offsets[i - 1];
|
||||
|
||||
/* Compressed blocks should be smaller than the uncompressed block size
|
||||
* but maybe compression performed poorly so the compressed block is
|
||||
* actually bigger. Clamp down on unrealistic values to prevent
|
||||
* ridiculous s->compressed_block allocation.
|
||||
*/
|
||||
if (size > 2 * MAX_BLOCK_SIZE) {
|
||||
error_setg(errp, "invalid compressed block size at index %u, "
|
||||
"image file is corrupt", i);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (size > max_compressed_block_size) {
|
||||
max_compressed_block_size = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize zlib engine */
|
||||
s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
||||
@@ -180,9 +243,7 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static void cloop_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
if (s->n_blocks > 0) {
|
||||
g_free(s->offsets);
|
||||
}
|
||||
g_free(s->compressed_block);
|
||||
g_free(s->uncompressed_block);
|
||||
inflateEnd(&s->zstream);
|
||||
|
@@ -157,6 +157,11 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
if (!s || !s->orig_buf)
|
||||
goto read_end;
|
||||
|
||||
if (s->buf_off >= s->buf_len) {
|
||||
/* buffer full, read nothing */
|
||||
return 0;
|
||||
}
|
||||
realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||
s->buf_off += realsize;
|
||||
|
||||
|
125
block/dmg.c
125
block/dmg.c
@@ -27,6 +27,14 @@
|
||||
#include "qemu/module.h"
|
||||
#include <zlib.h>
|
||||
|
||||
enum {
|
||||
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||
* or truncating when converting to 32-bit types
|
||||
*/
|
||||
DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
|
||||
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||
};
|
||||
|
||||
typedef struct BDRVDMGState {
|
||||
CoMutex lock;
|
||||
/* each chunk contains a certain number of sectors,
|
||||
@@ -92,6 +100,37 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Increase max chunk sizes, if necessary. This function is used to calculate
|
||||
* the buffer sizes needed for compressed/uncompressed chunk I/O.
|
||||
*/
|
||||
static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
|
||||
uint32_t *max_compressed_size,
|
||||
uint32_t *max_sectors_per_chunk)
|
||||
{
|
||||
uint32_t compressed_size = 0;
|
||||
uint32_t uncompressed_sectors = 0;
|
||||
|
||||
switch (s->types[chunk]) {
|
||||
case 0x80000005: /* zlib compressed */
|
||||
compressed_size = s->lengths[chunk];
|
||||
uncompressed_sectors = s->sectorcounts[chunk];
|
||||
break;
|
||||
case 1: /* copy */
|
||||
uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
|
||||
break;
|
||||
case 2: /* zero */
|
||||
uncompressed_sectors = s->sectorcounts[chunk];
|
||||
break;
|
||||
}
|
||||
|
||||
if (compressed_size > *max_compressed_size) {
|
||||
*max_compressed_size = compressed_size;
|
||||
}
|
||||
if (uncompressed_sectors > *max_sectors_per_chunk) {
|
||||
*max_sectors_per_chunk = uncompressed_sectors;
|
||||
}
|
||||
}
|
||||
|
||||
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -161,7 +200,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (type == 0x6d697368 && count >= 244) {
|
||||
int new_size, chunk_count;
|
||||
size_t new_size;
|
||||
uint32_t chunk_count;
|
||||
|
||||
offset += 4;
|
||||
offset += 200;
|
||||
@@ -180,10 +220,12 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
offset += 4;
|
||||
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
|
||||
if(s->types[i]==0xffffffff) {
|
||||
if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
|
||||
s->types[i] != 2) {
|
||||
if (s->types[i] == 0xffffffff && i > 0) {
|
||||
last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];
|
||||
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
|
||||
last_out_offset = s->sectors[i - 1] +
|
||||
s->sectorcounts[i - 1];
|
||||
}
|
||||
chunk_count--;
|
||||
i--;
|
||||
@@ -205,6 +247,14 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
offset += 8;
|
||||
|
||||
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||
error_report("sector count %" PRIu64 " for chunk %u is "
|
||||
"larger than max (%u)",
|
||||
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = read_uint64(bs, offset, &s->offsets[i]);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -218,10 +268,16 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
offset += 8;
|
||||
|
||||
if(s->lengths[i]>max_compressed_size)
|
||||
max_compressed_size = s->lengths[i];
|
||||
if(s->sectorcounts[i]>max_sectors_per_chunk)
|
||||
max_sectors_per_chunk = s->sectorcounts[i];
|
||||
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||
error_report("length %" PRIu64 " for chunk %u is larger "
|
||||
"than max (%u)",
|
||||
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
update_max_chunk_size(s, i, &max_compressed_size,
|
||||
&max_sectors_per_chunk);
|
||||
}
|
||||
s->n_chunks += chunk_count;
|
||||
}
|
||||
@@ -252,32 +308,34 @@ fail:
|
||||
}
|
||||
|
||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||
uint32_t chunk_num,int sector_num)
|
||||
uint32_t chunk_num, uint64_t sector_num)
|
||||
{
|
||||
if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
|
||||
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
|
||||
s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
|
||||
return 0;
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
|
||||
static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
|
||||
{
|
||||
/* binary search */
|
||||
uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
|
||||
while (chunk1 != chunk2) {
|
||||
chunk3 = (chunk1 + chunk2) / 2;
|
||||
if(s->sectors[chunk3]>sector_num)
|
||||
if (s->sectors[chunk3] > sector_num) {
|
||||
chunk2 = chunk3;
|
||||
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
|
||||
} else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
|
||||
return chunk3;
|
||||
else
|
||||
} else {
|
||||
chunk1 = chunk3;
|
||||
}
|
||||
}
|
||||
return s->n_chunks; /* error */
|
||||
}
|
||||
|
||||
static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
|
||||
@@ -285,44 +343,41 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
int ret;
|
||||
uint32_t chunk = search_chunk(s, sector_num);
|
||||
|
||||
if(chunk>=s->n_chunks)
|
||||
if (chunk >= s->n_chunks) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->current_chunk = s->n_chunks;
|
||||
switch (s->types[chunk]) {
|
||||
case 0x80000005: { /* zlib compressed */
|
||||
int i;
|
||||
|
||||
/* we need to buffer, because only the chunk as whole can be
|
||||
* inflated. */
|
||||
i=0;
|
||||
do {
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
||||
s->compressed_chunk+i, s->lengths[chunk]-i);
|
||||
if(ret<0 && errno==EINTR)
|
||||
ret=0;
|
||||
i+=ret;
|
||||
} while(ret>=0 && ret+i<s->lengths[chunk]);
|
||||
|
||||
if (ret != s->lengths[chunk])
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->compressed_chunk, s->lengths[chunk]);
|
||||
if (ret != s->lengths[chunk]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->zstream.next_in = s->compressed_chunk;
|
||||
s->zstream.avail_in = s->lengths[chunk];
|
||||
s->zstream.next_out = s->uncompressed_chunk;
|
||||
s->zstream.avail_out = 512 * s->sectorcounts[chunk];
|
||||
ret = inflateReset(&s->zstream);
|
||||
if(ret != Z_OK)
|
||||
if (ret != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
ret = inflate(&s->zstream, Z_FINISH);
|
||||
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
|
||||
if (ret != Z_STREAM_END ||
|
||||
s->zstream.total_out != 512 * s->sectorcounts[chunk]) {
|
||||
return -1;
|
||||
}
|
||||
break; }
|
||||
case 1: /* copy */
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->uncompressed_chunk, s->lengths[chunk]);
|
||||
if (ret != s->lengths[chunk])
|
||||
if (ret != s->lengths[chunk]) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 2: /* zero */
|
||||
memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]);
|
||||
@@ -341,10 +396,12 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
for (i = 0; i < nb_sectors; i++) {
|
||||
uint32_t sector_offset_in_chunk;
|
||||
if(dmg_read_chunk(bs, sector_num+i) != 0)
|
||||
if (dmg_read_chunk(bs, sector_num + i) != 0) {
|
||||
return -1;
|
||||
}
|
||||
sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
|
||||
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
|
||||
memcpy(buf + i * 512,
|
||||
s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -417,6 +417,10 @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
|
||||
if (bs->sg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
retry:
|
||||
@@ -838,7 +842,8 @@ retry:
|
||||
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||
(iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE ||
|
||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB)) {
|
||||
/* WRITE SAME is not supported by the target */
|
||||
iscsilun->has_write_same = false;
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
@@ -1096,8 +1101,10 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
||||
return task;
|
||||
|
||||
fail:
|
||||
if (!error_is_set(errp)) {
|
||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||
iscsi_get_error(iscsi));
|
||||
}
|
||||
if (task != NULL) {
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
@@ -1330,18 +1337,20 @@ static int iscsi_refresh_limits(BlockDriverState *bs)
|
||||
|
||||
/* We don't actually refresh here, but just return data queried in
|
||||
* iscsi_open(): iscsi targets don't change their limits. */
|
||||
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
||||
if (iscsilun->lbp.lbpu) {
|
||||
if (iscsilun->bl.max_unmap < 0xffffffff) {
|
||||
bs->bl.max_discard = sector_lun2qemu(iscsilun->bl.max_unmap,
|
||||
iscsilun);
|
||||
}
|
||||
bs->bl.discard_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||
iscsilun);
|
||||
}
|
||||
|
||||
if (iscsilun->bl.max_ws_len < 0xffffffff) {
|
||||
bs->bl.max_write_zeroes = sector_lun2qemu(iscsilun->bl.max_ws_len,
|
||||
iscsilun);
|
||||
}
|
||||
if (iscsilun->lbp.lbpws) {
|
||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||
iscsilun);
|
||||
}
|
||||
|
@@ -49,9 +49,9 @@ typedef struct BDRVParallelsState {
|
||||
CoMutex lock;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
int catalog_size;
|
||||
unsigned int catalog_size;
|
||||
|
||||
int tracks;
|
||||
unsigned int tracks;
|
||||
} BDRVParallelsState;
|
||||
|
||||
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
@@ -93,8 +93,18 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
||||
|
||||
s->tracks = le32_to_cpu(ph.tracks);
|
||||
if (s->tracks == 0) {
|
||||
error_setg(errp, "Invalid image: Zero sectors per track");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||
if (s->catalog_size > INT_MAX / 4) {
|
||||
error_setg(errp, "Catalog too large");
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||
|
||||
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
||||
|
@@ -55,7 +55,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
}
|
||||
}
|
||||
|
||||
if (new_l1_size > INT_MAX) {
|
||||
if (new_l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
@@ -359,15 +359,6 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
||||
struct iovec iov;
|
||||
int n, ret;
|
||||
|
||||
/*
|
||||
* If this is the last cluster and it is only partially used, we must only
|
||||
* copy until the end of the image, or bdrv_check_request will fail for the
|
||||
* bdrv_read/write calls below.
|
||||
*/
|
||||
if (start_sect + n_end > bs->total_sectors) {
|
||||
n_end = bs->total_sectors - start_sect;
|
||||
}
|
||||
|
||||
n = n_end - n_start;
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
@@ -500,6 +491,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
break;
|
||||
case QCOW2_CLUSTER_ZERO:
|
||||
if (s->qcow_version < 3) {
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
return -EIO;
|
||||
}
|
||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||
|
@@ -28,7 +28,7 @@
|
||||
#include "qemu/range.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int64_t offset, int64_t length,
|
||||
int addend, enum qcow2_discard_type type);
|
||||
@@ -40,8 +40,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int qcow2_refcount_init(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int ret, refcount_table_size2, i;
|
||||
unsigned int refcount_table_size2, i;
|
||||
int ret;
|
||||
|
||||
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||
s->refcount_table = g_malloc(refcount_table_size2);
|
||||
if (s->refcount_table_size > 0) {
|
||||
@@ -87,7 +89,7 @@ static int load_refcount_block(BlockDriverState *bs,
|
||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int refcount_table_index, block_index;
|
||||
uint64_t refcount_table_index, block_index;
|
||||
int64_t refcount_block_offset;
|
||||
int ret;
|
||||
uint16_t *refcount_block;
|
||||
@@ -192,10 +194,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
* they can describe them themselves.
|
||||
*
|
||||
* - We need to consider that at this point we are inside update_refcounts
|
||||
* and doing the initial refcount increase. This means that some clusters
|
||||
* have already been allocated by the caller, but their refcount isn't
|
||||
* accurate yet. free_cluster_index tells us where this allocation ends
|
||||
* as long as we don't overwrite it by freeing clusters.
|
||||
* and potentially doing an initial refcount increase. This means that
|
||||
* some clusters have already been allocated by the caller, but their
|
||||
* refcount isn't accurate yet. If we allocate clusters for metadata, we
|
||||
* need to return -EAGAIN to signal the caller that it needs to restart
|
||||
* the search for free clusters.
|
||||
*
|
||||
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||
* refcount block into the cache
|
||||
@@ -280,7 +283,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
s->refcount_table[refcount_table_index] = new_block;
|
||||
return 0;
|
||||
|
||||
/* The new refcount block may be where the caller intended to put its
|
||||
* data, so let it restart the search. */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
||||
@@ -303,8 +309,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
|
||||
/* Calculate the number of refcount blocks needed so far */
|
||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
uint64_t blocks_used = (s->free_cluster_index +
|
||||
refcount_block_clusters - 1) / refcount_block_clusters;
|
||||
uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
|
||||
|
||||
if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
/* And now we need at least one block more for the new metadata */
|
||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||
@@ -337,8 +346,6 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
||||
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
||||
|
||||
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
||||
|
||||
/* Fill the new refcount table */
|
||||
memcpy(new_table, s->refcount_table,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
@@ -401,18 +408,19 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
s->refcount_table_size = table_size;
|
||||
s->refcount_table_offset = table_offset;
|
||||
|
||||
/* Free old table. Remember, we must not change free_cluster_index */
|
||||
uint64_t old_free_cluster_index = s->free_cluster_index;
|
||||
/* Free old table. */
|
||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
||||
QCOW2_DISCARD_OTHER);
|
||||
s->free_cluster_index = old_free_cluster_index;
|
||||
|
||||
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* If we were trying to do the initial refcount update for some cluster
|
||||
* allocation, we might have used the same clusters to store newly
|
||||
* allocated metadata. Make the caller search some new space. */
|
||||
return -EAGAIN;
|
||||
|
||||
fail_table:
|
||||
g_free(new_table);
|
||||
@@ -627,15 +635,16 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
|
||||
|
||||
|
||||
/* return < 0 if error */
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int i, nb_clusters, refcount;
|
||||
uint64_t i, nb_clusters;
|
||||
int refcount;
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
retry:
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
int64_t next_cluster_index = s->free_cluster_index++;
|
||||
uint64_t next_cluster_index = s->free_cluster_index++;
|
||||
refcount = get_refcount(bs, next_cluster_index);
|
||||
|
||||
if (refcount < 0) {
|
||||
@@ -652,18 +661,21 @@ retry:
|
||||
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
||||
}
|
||||
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||
{
|
||||
int64_t offset;
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||
do {
|
||||
offset = alloc_clusters_noref(bs, size);
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -676,7 +688,6 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_index;
|
||||
uint64_t old_free_cluster_index;
|
||||
uint64_t i;
|
||||
int refcount, ret;
|
||||
|
||||
@@ -685,6 +696,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
/* Check how many clusters there are free */
|
||||
cluster_index = offset >> s->cluster_bits;
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
@@ -698,17 +710,14 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
/* And then allocate them */
|
||||
old_free_cluster_index = s->free_cluster_index;
|
||||
s->free_cluster_index = cluster_index + i;
|
||||
|
||||
ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
||||
QCOW2_DISCARD_NEVER);
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->free_cluster_index = old_free_cluster_index;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -1011,8 +1020,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
int64_t offset, int64_t size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t start, last, cluster_offset;
|
||||
int k;
|
||||
uint64_t start, last, cluster_offset, k;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
@@ -1022,11 +1030,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
cluster_offset += s->cluster_size) {
|
||||
k = cluster_offset >> s->cluster_bits;
|
||||
if (k < 0) {
|
||||
fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
||||
cluster_offset);
|
||||
res->corruptions++;
|
||||
} else if (k >= refcount_table_size) {
|
||||
if (k >= refcount_table_size) {
|
||||
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
||||
"the end of the image file, can't properly check refcounts.\n",
|
||||
cluster_offset);
|
||||
@@ -1469,14 +1473,19 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
BdrvCheckMode fix)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t size, i, highest_cluster;
|
||||
int nb_clusters, refcount1, refcount2;
|
||||
int64_t size, i, highest_cluster, nb_clusters;
|
||||
int refcount1, refcount2;
|
||||
QCowSnapshot *sn;
|
||||
uint16_t *refcount_table;
|
||||
int ret;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
if (nb_clusters > INT_MAX) {
|
||||
res->check_errors++;
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
||||
|
||||
res->bfi.total_clusters =
|
||||
|
@@ -26,31 +26,6 @@
|
||||
#include "block/block_int.h"
|
||||
#include "block/qcow2.h"
|
||||
|
||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||
/* header is 8 byte aligned */
|
||||
uint64_t l1_table_offset;
|
||||
|
||||
uint32_t l1_size;
|
||||
uint16_t id_str_size;
|
||||
uint16_t name_size;
|
||||
|
||||
uint32_t date_sec;
|
||||
uint32_t date_nsec;
|
||||
|
||||
uint64_t vm_clock_nsec;
|
||||
|
||||
uint32_t vm_state_size;
|
||||
uint32_t extra_data_size; /* for extension */
|
||||
/* extra data follows */
|
||||
/* id_str follows */
|
||||
/* name follows */
|
||||
} QCowSnapshotHeader;
|
||||
|
||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||
uint64_t vm_state_size_large;
|
||||
uint64_t disk_size;
|
||||
} QCowSnapshotExtraData;
|
||||
|
||||
void qcow2_free_snapshots(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -141,8 +116,14 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
||||
}
|
||||
offset += name_size;
|
||||
sn->name[name_size] = '\0';
|
||||
|
||||
if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
assert(offset - s->snapshots_offset <= INT_MAX);
|
||||
s->snapshots_size = offset - s->snapshots_offset;
|
||||
return 0;
|
||||
|
||||
@@ -163,7 +144,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||
uint32_t nb_snapshots;
|
||||
uint64_t snapshots_offset;
|
||||
} QEMU_PACKED header_data;
|
||||
int64_t offset, snapshots_offset;
|
||||
int64_t offset, snapshots_offset = 0;
|
||||
int ret;
|
||||
|
||||
/* compute the size of the snapshots */
|
||||
@@ -175,7 +156,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||
offset += sizeof(extra);
|
||||
offset += strlen(sn->id_str);
|
||||
offset += strlen(sn->name);
|
||||
|
||||
if (offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
assert(offset <= INT_MAX);
|
||||
snapshots_size = offset;
|
||||
|
||||
/* Allocate space for the new snapshot list */
|
||||
@@ -357,6 +345,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
uint64_t *l1_table = NULL;
|
||||
int64_t l1_table_offset;
|
||||
|
||||
if (s->nb_snapshots >= QCOW_MAX_SNAPSHOTS) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
memset(sn, 0, sizeof(*sn));
|
||||
|
||||
/* Generate an ID if it wasn't passed */
|
||||
@@ -701,7 +693,11 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||
sn = &s->snapshots[snapshot_index];
|
||||
|
||||
/* Allocate and read in the snapshot's L1 table */
|
||||
new_l1_bytes = s->l1_size * sizeof(uint64_t);
|
||||
if (sn->l1_size > QCOW_MAX_L1_SIZE) {
|
||||
error_setg(errp, "Snapshot L1 table too large");
|
||||
return -EFBIG;
|
||||
}
|
||||
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
||||
|
||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||
|
170
block/qcow2.c
170
block/qcow2.c
@@ -269,12 +269,15 @@ static int qcow2_mark_clean(BlockDriverState *bs)
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
|
||||
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
|
||||
int ret = bdrv_flush(bs);
|
||||
int ret;
|
||||
|
||||
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
||||
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
|
||||
return qcow2_update_header(bs);
|
||||
}
|
||||
return 0;
|
||||
@@ -329,6 +332,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t entries, size_t entry_len)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t size;
|
||||
|
||||
/* Use signed INT64_MAX as the maximum even for uint64_t header fields,
|
||||
* because values will be passed to qemu functions taking int64_t. */
|
||||
if (entries > INT64_MAX / entry_len) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = entries * entry_len;
|
||||
|
||||
if (INT64_MAX - size < offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Tables must be cluster aligned */
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QemuOptsList qcow2_runtime_opts = {
|
||||
.name = "qcow2",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
||||
@@ -419,7 +448,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, ret = 0;
|
||||
unsigned int len, i;
|
||||
int ret = 0;
|
||||
QCowHeader header;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
@@ -460,6 +490,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->qcow_version = header.version;
|
||||
|
||||
/* Initialise cluster size */
|
||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->cluster_bits = header.cluster_bits;
|
||||
s->cluster_size = 1 << s->cluster_bits;
|
||||
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||
|
||||
/* Initialise version 3 header fields */
|
||||
if (header.version == 2) {
|
||||
header.incompatible_features = 0;
|
||||
@@ -473,6 +515,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
be64_to_cpus(&header.autoclear_features);
|
||||
be32_to_cpus(&header.refcount_order);
|
||||
be32_to_cpus(&header.header_length);
|
||||
|
||||
if (header.header_length < 104) {
|
||||
error_setg(errp, "qcow2 header too short");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (header.header_length > s->cluster_size) {
|
||||
error_setg(errp, "qcow2 header exceeds cluster size");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.header_length > sizeof(header)) {
|
||||
@@ -487,6 +541,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (header.backing_file_offset > s->cluster_size) {
|
||||
error_setg(errp, "Invalid backing file offset");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.backing_file_offset) {
|
||||
ext_end = header.backing_file_offset;
|
||||
} else {
|
||||
@@ -506,6 +566,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->incompatible_features &
|
||||
~QCOW2_INCOMPAT_MASK);
|
||||
ret = -ENOTSUP;
|
||||
g_free(feature_table);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -529,12 +590,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
s->refcount_order = header.refcount_order;
|
||||
|
||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "Unsupported encryption method: %i",
|
||||
header.crypt_method);
|
||||
@@ -545,23 +600,52 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (s->crypt_method_header) {
|
||||
bs->encrypted = 1;
|
||||
}
|
||||
s->cluster_bits = header.cluster_bits;
|
||||
s->cluster_size = 1 << s->cluster_bits;
|
||||
s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||
|
||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||
s->l2_size = 1 << s->l2_bits;
|
||||
bs->total_sectors = header.size / 512;
|
||||
s->csize_shift = (62 - (s->cluster_bits - 8));
|
||||
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
||||
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
||||
|
||||
s->refcount_table_offset = header.refcount_table_offset;
|
||||
s->refcount_table_size =
|
||||
header.refcount_table_clusters << (s->cluster_bits - 3);
|
||||
|
||||
s->snapshots_offset = header.snapshots_offset;
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
|
||||
error_setg(errp, "Reference count table too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = validate_table_offset(bs, s->refcount_table_offset,
|
||||
s->refcount_table_size, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Invalid reference count table offset");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Snapshot table offset/length */
|
||||
if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
|
||||
error_setg(errp, "Too many snapshots");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = validate_table_offset(bs, header.snapshots_offset,
|
||||
header.nb_snapshots,
|
||||
sizeof(QCowSnapshotHeader));
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Invalid snapshot table offset");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read the level 1 table */
|
||||
if (header.l1_size > QCOW_MAX_L1_SIZE) {
|
||||
error_setg(errp, "Active L1 table too large");
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
s->l1_size = header.l1_size;
|
||||
|
||||
l1_vm_state_index = size_to_l1(s, header.size);
|
||||
@@ -579,7 +663,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = validate_table_offset(bs, header.l1_table_offset,
|
||||
header.l1_size, sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Invalid L1 table offset");
|
||||
goto fail;
|
||||
}
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
|
||||
|
||||
if (s->l1_size > 0) {
|
||||
s->l1_table = g_malloc0(
|
||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
||||
@@ -625,8 +718,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* read the backing file name */
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023) {
|
||||
len = 1023;
|
||||
if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) {
|
||||
error_setg(errp, "Backing file name too long");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
||||
@@ -637,6 +732,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
|
||||
/* Internal snapshots */
|
||||
s->snapshots_offset = header.snapshots_offset;
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
|
||||
ret = qcow2_read_snapshots(bs);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not read snapshots");
|
||||
@@ -745,6 +844,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (s->l2_table_cache) {
|
||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||
}
|
||||
if (s->refcount_block_cache) {
|
||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||
}
|
||||
g_free(s->cluster_cache);
|
||||
qemu_vfree(s->cluster_data);
|
||||
return ret;
|
||||
@@ -801,11 +903,25 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We have nothing to do for QCOW2 reopen, stubs just return
|
||||
* success */
|
||||
/* We have no actual commit/abort logic for qcow2, but we need to write out any
|
||||
* unwritten data if we reopen read-only. */
|
||||
static int qcow2_reopen_prepare(BDRVReopenState *state,
|
||||
BlockReopenQueue *queue, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((state->flags & BDRV_O_RDWR) == 0) {
|
||||
ret = bdrv_flush(state->bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcow2_mark_clean(state->bs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1432,7 +1548,9 @@ static int preallocate(BlockDriverState *bs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (meta != NULL) {
|
||||
while (meta) {
|
||||
QCowL2Meta *next = meta->next;
|
||||
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||
if (ret < 0) {
|
||||
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
||||
@@ -1443,6 +1561,9 @@ static int preallocate(BlockDriverState *bs)
|
||||
/* There are no dependent requests, but we need to remove our
|
||||
* request from the list of in-flight requests */
|
||||
QLIST_REMOVE(meta, next_in_flight);
|
||||
|
||||
g_free(meta);
|
||||
meta = next;
|
||||
}
|
||||
|
||||
/* TODO Preallocate data if requested */
|
||||
@@ -1500,7 +1621,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
*/
|
||||
BlockDriverState* bs;
|
||||
QCowHeader *header;
|
||||
uint8_t* refcount_table;
|
||||
uint64_t* refcount_table;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -1552,9 +1673,10 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Write an empty refcount table */
|
||||
refcount_table = g_malloc0(cluster_size);
|
||||
ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
|
||||
/* Write a refcount table with one refcount block */
|
||||
refcount_table = g_malloc0(2 * cluster_size);
|
||||
refcount_table[0] = cpu_to_be64(2 * cluster_size);
|
||||
ret = bdrv_pwrite(bs, cluster_size, refcount_table, 2 * cluster_size);
|
||||
g_free(refcount_table);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1579,7 +1701,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
|
||||
ret = qcow2_alloc_clusters(bs, 3 * cluster_size);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
|
||||
"header and refcount table");
|
||||
|
@@ -38,6 +38,19 @@
|
||||
#define QCOW_CRYPT_AES 1
|
||||
|
||||
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
||||
#define QCOW_MAX_SNAPSHOTS 65536
|
||||
|
||||
/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
#define QCOW_MAX_REFTABLE_SIZE 0x800000
|
||||
|
||||
/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
#define QCOW_MAX_L1_SIZE 0x2000000
|
||||
|
||||
/* Allow for an average of 1k per snapshot table entry, should be plenty of
|
||||
* space for snapshot names and IDs */
|
||||
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
|
||||
|
||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||
#define QCOW_OFLAG_COPIED (1ULL << 63)
|
||||
@@ -97,6 +110,32 @@ typedef struct QCowHeader {
|
||||
uint32_t header_length;
|
||||
} QEMU_PACKED QCowHeader;
|
||||
|
||||
typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||
/* header is 8 byte aligned */
|
||||
uint64_t l1_table_offset;
|
||||
|
||||
uint32_t l1_size;
|
||||
uint16_t id_str_size;
|
||||
uint16_t name_size;
|
||||
|
||||
uint32_t date_sec;
|
||||
uint32_t date_nsec;
|
||||
|
||||
uint64_t vm_clock_nsec;
|
||||
|
||||
uint32_t vm_state_size;
|
||||
uint32_t extra_data_size; /* for extension */
|
||||
/* extra data follows */
|
||||
/* id_str follows */
|
||||
/* name follows */
|
||||
} QCowSnapshotHeader;
|
||||
|
||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||
uint64_t vm_state_size_large;
|
||||
uint64_t disk_size;
|
||||
} QCowSnapshotExtraData;
|
||||
|
||||
|
||||
typedef struct QCowSnapshot {
|
||||
uint64_t l1_table_offset;
|
||||
uint32_t l1_size;
|
||||
@@ -191,8 +230,8 @@ typedef struct BDRVQcowState {
|
||||
uint64_t *refcount_table;
|
||||
uint64_t refcount_table_offset;
|
||||
uint32_t refcount_table_size;
|
||||
int64_t free_cluster_index;
|
||||
int64_t free_byte_offset;
|
||||
uint64_t free_cluster_index;
|
||||
uint64_t free_byte_offset;
|
||||
|
||||
CoMutex lock;
|
||||
|
||||
@@ -202,7 +241,7 @@ typedef struct BDRVQcowState {
|
||||
AES_KEY aes_decrypt_key;
|
||||
uint64_t snapshots_offset;
|
||||
int snapshots_size;
|
||||
int nb_snapshots;
|
||||
unsigned int nb_snapshots;
|
||||
QCowSnapshot *snapshots;
|
||||
|
||||
int flags;
|
||||
@@ -383,6 +422,11 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcowState *s)
|
||||
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
||||
}
|
||||
|
||||
static inline uint64_t qcow2_max_refcount_clusters(BDRVQcowState *s)
|
||||
{
|
||||
return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
|
||||
}
|
||||
|
||||
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
||||
{
|
||||
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
||||
@@ -431,7 +475,7 @@ void qcow2_refcount_close(BlockDriverState *bs);
|
||||
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||
int addend, enum qcow2_discard_type type);
|
||||
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int nb_clusters);
|
||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
||||
|
37
block/vdi.c
37
block/vdi.c
@@ -120,6 +120,11 @@ typedef unsigned char uuid_t[16];
|
||||
|
||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||
|
||||
/* max blocks in image is (0xffffffff / 4) */
|
||||
#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
|
||||
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||
(uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||
|
||||
#if !defined(CONFIG_UUID)
|
||||
static inline void uuid_generate(uuid_t out)
|
||||
{
|
||||
@@ -385,6 +390,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
vdi_header_print(&header);
|
||||
#endif
|
||||
|
||||
if (header.disk_size > VDI_DISK_SIZE_MAX) {
|
||||
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||
", max supported is 0x%" PRIx64 ")",
|
||||
header.disk_size, VDI_DISK_SIZE_MAX);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.disk_size % SECTOR_SIZE != 0) {
|
||||
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
||||
We accept them but round the disk size to the next multiple of
|
||||
@@ -420,9 +433,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
header.sector_size, SECTOR_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.block_size != 1 * MiB) {
|
||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
||||
header.block_size, 1 * MiB);
|
||||
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
||||
header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.disk_size >
|
||||
@@ -441,6 +454,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
error_setg(errp, "unsupported VDI image (non-NULL parent UUID)");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.blocks_in_image > VDI_BLOCKS_IN_IMAGE_MAX) {
|
||||
error_setg(errp, "unsupported VDI image "
|
||||
"(too many blocks %u, max is %u)",
|
||||
header.blocks_in_image, VDI_BLOCKS_IN_IMAGE_MAX);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
||||
@@ -689,11 +708,20 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
options++;
|
||||
}
|
||||
|
||||
if (bytes > VDI_DISK_SIZE_MAX) {
|
||||
result = -ENOTSUP;
|
||||
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||
", max supported is 0x%" PRIx64 ")",
|
||||
bytes, VDI_DISK_SIZE_MAX);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fd = qemu_open(filename,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
result = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* We need enough blocks to store the given disk size,
|
||||
@@ -754,6 +782,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
12
block/vhdx.c
12
block/vhdx.c
@@ -780,12 +780,20 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
||||
le32_to_cpus(&s->logical_sector_size);
|
||||
le32_to_cpus(&s->physical_sector_size);
|
||||
|
||||
if (s->logical_sector_size == 0 || s->params.block_size == 0) {
|
||||
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
|
||||
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* both block_size and sector_size are guaranteed powers of 2 */
|
||||
/* only 2 supported sector sizes */
|
||||
if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Both block_size and sector_size are guaranteed powers of 2, below.
|
||||
Due to range checks above, s->sectors_per_block can never be < 256 */
|
||||
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
||||
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
||||
(uint64_t)s->logical_sector_size /
|
||||
|
32
block/vpc.c
32
block/vpc.c
@@ -45,6 +45,8 @@ enum vhd_type {
|
||||
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
||||
#define VHD_TIMESTAMP_BASE 946684800
|
||||
|
||||
#define VHD_MAX_SECTORS (65535LL * 255 * 255)
|
||||
|
||||
// always big-endian
|
||||
typedef struct vhd_footer {
|
||||
char creator[8]; // "conectix"
|
||||
@@ -164,6 +166,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
VHDDynDiskHeader *dyndisk_header;
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
uint64_t computed_size;
|
||||
int disk_type = VHD_DYNAMIC;
|
||||
int ret;
|
||||
|
||||
@@ -222,7 +225,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Allow a maximum disk size of approximately 2 TB */
|
||||
if (bs->total_sectors >= 65535LL * 255 * 255) {
|
||||
if (bs->total_sectors >= VHD_MAX_SECTORS) {
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
@@ -242,10 +245,31 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
||||
if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
|
||||
error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
||||
|
||||
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
||||
s->pagetable = g_malloc(s->max_table_entries * 4);
|
||||
|
||||
if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
computed_size = (uint64_t) s->max_table_entries * s->block_size;
|
||||
if (computed_size < bs->total_sectors * 512) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
|
||||
@@ -298,7 +322,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
g_free(s->pagetable);
|
||||
qemu_vfree(s->pagetable);
|
||||
#ifdef CACHE
|
||||
g_free(s->pageentry_u8);
|
||||
#endif
|
||||
@@ -833,7 +857,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
||||
static void vpc_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
g_free(s->pagetable);
|
||||
qemu_vfree(s->pagetable);
|
||||
#ifdef CACHE
|
||||
g_free(s->pageentry_u8);
|
||||
#endif
|
||||
|
@@ -1119,6 +1119,7 @@ DLOG(if (stderr == NULL) {
|
||||
if (!s->fat_type) {
|
||||
s->fat_type = 16;
|
||||
}
|
||||
s->first_sectors_number = 0x40;
|
||||
cyls = s->fat_type == 12 ? 64 : 1024;
|
||||
heads = 16;
|
||||
secs = 63;
|
||||
@@ -1146,7 +1147,6 @@ DLOG(if (stderr == NULL) {
|
||||
|
||||
s->current_cluster=0xffffffff;
|
||||
|
||||
s->first_sectors_number=0x40;
|
||||
/* read only is the default for safety */
|
||||
bs->read_only = 1;
|
||||
s->qcow = s->write_target = NULL;
|
||||
|
@@ -227,6 +227,8 @@ int cpu_exec(CPUArchState *env)
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
uintptr_t next_tb;
|
||||
/* This must be volatile so it is not trashed by longjmp() */
|
||||
volatile bool have_tb_lock = false;
|
||||
|
||||
if (cpu->halted) {
|
||||
if (!cpu_has_work(cpu)) {
|
||||
@@ -600,6 +602,7 @@ int cpu_exec(CPUArchState *env)
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
spin_lock(&tcg_ctx.tb_ctx.tb_lock);
|
||||
have_tb_lock = true;
|
||||
tb = tb_find_fast(env);
|
||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||
doing it in tb_find_slow */
|
||||
@@ -621,6 +624,7 @@ int cpu_exec(CPUArchState *env)
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||
next_tb & TB_EXIT_MASK, tb);
|
||||
}
|
||||
have_tb_lock = false;
|
||||
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||
|
||||
/* cpu_interrupt might be called while translating the
|
||||
@@ -692,6 +696,10 @@ int cpu_exec(CPUArchState *env)
|
||||
#ifdef TARGET_I386
|
||||
x86_cpu = X86_CPU(cpu);
|
||||
#endif
|
||||
if (have_tb_lock) {
|
||||
spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
|
||||
have_tb_lock = false;
|
||||
}
|
||||
}
|
||||
} /* for(;;) */
|
||||
|
||||
|
@@ -213,6 +213,7 @@ BlockDriverAIOCB *dma_bdrv_io(
|
||||
dbs->sg_cur_index = 0;
|
||||
dbs->sg_cur_byte = 0;
|
||||
dbs->dir = dir;
|
||||
dbs->in_cancel = false;
|
||||
dbs->io_func = io_func;
|
||||
dbs->bh = NULL;
|
||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||
|
@@ -230,18 +230,23 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
Error *err = NULL;
|
||||
|
||||
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
|
||||
|
||||
object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
|
||||
&err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
if (!oc) {
|
||||
error_report("Unable to find CPU definition");
|
||||
exit(1);
|
||||
}
|
||||
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
|
||||
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, MPCORE_PERIPHBASE,
|
||||
"reset-cbar", &error_abort);
|
||||
}
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
|
@@ -192,10 +192,9 @@ static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, periphbase,
|
||||
"reset-cbar", &error_abort);
|
||||
}
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "virtio-blk.h"
|
||||
#include "block/aio.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "monitor/monitor.h" /* for object_add() */
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
enum {
|
||||
SEG_MAX = 126, /* maximum number of I/O segments */
|
||||
@@ -59,7 +59,7 @@ struct VirtIOBlockDataPlane {
|
||||
* use it).
|
||||
*/
|
||||
IOThread *iothread;
|
||||
bool internal_iothread;
|
||||
IOThread internal_iothread_obj;
|
||||
AioContext *ctx;
|
||||
EventNotifier io_notifier; /* Linux AIO completion */
|
||||
EventNotifier host_notifier; /* doorbell */
|
||||
@@ -391,23 +391,19 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
s->blk = blk;
|
||||
|
||||
if (blk->iothread) {
|
||||
s->internal_iothread = false;
|
||||
s->iothread = blk->iothread;
|
||||
} else {
|
||||
/* Create per-device IOThread if none specified */
|
||||
Error *local_err = NULL;
|
||||
|
||||
s->internal_iothread = true;
|
||||
object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
g_free(s);
|
||||
return;
|
||||
}
|
||||
s->iothread = iothread_find(vdev->name);
|
||||
assert(s->iothread);
|
||||
}
|
||||
object_ref(OBJECT(s->iothread));
|
||||
} else {
|
||||
/* Create per-device IOThread if none specified. This is for
|
||||
* x-data-plane option compatibility. If x-data-plane is removed we
|
||||
* can drop this.
|
||||
*/
|
||||
object_initialize(&s->internal_iothread_obj,
|
||||
sizeof(s->internal_iothread_obj),
|
||||
TYPE_IOTHREAD);
|
||||
user_creatable_complete(OBJECT(&s->internal_iothread_obj), &error_abort);
|
||||
s->iothread = &s->internal_iothread_obj;
|
||||
}
|
||||
s->ctx = iothread_get_aio_context(s->iothread);
|
||||
|
||||
/* Prevent block operations that conflict with data plane thread */
|
||||
@@ -426,9 +422,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
||||
virtio_blk_data_plane_stop(s);
|
||||
bdrv_set_in_use(s->blk->conf.bs, 0);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
if (s->internal_iothread) {
|
||||
object_unparent(OBJECT(s->iothread));
|
||||
}
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
|
@@ -753,7 +753,7 @@ static int nvme_init(PCIDevice *pci_dev)
|
||||
}
|
||||
|
||||
bs_size = bdrv_getlength(n->conf.bs);
|
||||
if (bs_size <= 0) {
|
||||
if (bs_size < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -225,8 +225,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
|
||||
if (s->tsr_retry <= 0) {
|
||||
if (s->fcr & UART_FCR_FE) {
|
||||
s->tsr = fifo8_is_empty(&s->xmit_fifo) ?
|
||||
0 : fifo8_pop(&s->xmit_fifo);
|
||||
if (fifo8_is_empty(&s->xmit_fifo)) {
|
||||
return FALSE;
|
||||
}
|
||||
s->tsr = fifo8_pop(&s->xmit_fifo);
|
||||
if (!s->xmit_fifo.num) {
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
}
|
||||
|
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* 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; under version 2 of the License.
|
||||
* 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
|
||||
|
@@ -117,7 +117,12 @@ void apic_report_irq_delivered(int delivered)
|
||||
|
||||
void apic_reset_irq_delivered(void)
|
||||
{
|
||||
trace_apic_reset_irq_delivered(apic_irq_delivered);
|
||||
/* Copy this into a local variable to encourage gcc to emit a plain
|
||||
* register for a sys/sdt.h marker. For details on this workaround, see:
|
||||
* https://sourceware.org/bugzilla/show_bug.cgi?id=13296
|
||||
*/
|
||||
volatile int a_i_d = apic_irq_delivered;
|
||||
trace_apic_reset_irq_delivered(a_i_d);
|
||||
|
||||
apic_irq_delivered = 0;
|
||||
}
|
||||
|
@@ -118,6 +118,11 @@ static void kvm_openpic_region_add(MemoryListener *listener,
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Ignore events on regions that are not us */
|
||||
if (section->mr != &opp->mem) {
|
||||
return;
|
||||
}
|
||||
|
||||
reg_base = section->offset_within_address_space;
|
||||
|
||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||
@@ -140,6 +145,11 @@ static void kvm_openpic_region_del(MemoryListener *listener,
|
||||
uint64_t reg_base = 0;
|
||||
int ret;
|
||||
|
||||
/* Ignore events on regions that are not us */
|
||||
if (section->mr != &opp->mem) {
|
||||
return;
|
||||
}
|
||||
|
||||
attr.group = KVM_DEV_MPIC_GRP_MISC;
|
||||
attr.attr = KVM_DEV_MPIC_BASE_ADDR;
|
||||
attr.addr = (uint64_t)(unsigned long)®_base;
|
||||
|
@@ -56,12 +56,14 @@ static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
TMP105State *s = TMP105(obj);
|
||||
int64_t value = s->temperature;
|
||||
int64_t value = s->temperature * 1000 / 256;
|
||||
|
||||
visit_type_int(v, &value, name, errp);
|
||||
}
|
||||
|
||||
/* Units are 0.001 centigrades relative to 0 C. */
|
||||
/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
|
||||
* fixed point, so units are 1/256 centigrades. A simple ratio will do.
|
||||
*/
|
||||
static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
@@ -78,7 +80,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
|
||||
return;
|
||||
}
|
||||
|
||||
s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
|
||||
s->temperature = (int16_t) (temp * 256 / 1000);
|
||||
|
||||
tmp105_alarm_update(s);
|
||||
}
|
||||
|
@@ -101,7 +101,6 @@ static void scsi_dma_restart_bh(void *opaque)
|
||||
scsi_req_continue(req);
|
||||
break;
|
||||
case SCSI_XFER_NONE:
|
||||
assert(!req->sg);
|
||||
scsi_req_dequeue(req);
|
||||
scsi_req_enqueue(req);
|
||||
break;
|
||||
|
@@ -190,6 +190,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||
QDict *options, const char *bdref_key, int flags,
|
||||
bool allow_none, Error **errp);
|
||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
||||
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp);
|
||||
int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
BlockDriver *drv, Error **errp);
|
||||
|
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* 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; under version 2 of the License.
|
||||
* 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
|
||||
|
@@ -11,6 +11,8 @@
|
||||
# include <sys/endian.h>
|
||||
# include <sys/types.h>
|
||||
# include <machine/bswap.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <sys/endian.h>
|
||||
#elif defined(CONFIG_BYTESWAP_H)
|
||||
# include <byteswap.h>
|
||||
|
||||
|
@@ -15,10 +15,20 @@
|
||||
#define IOTHREAD_H
|
||||
|
||||
#include "block/aio.h"
|
||||
#include "qemu/thread.h"
|
||||
|
||||
#define TYPE_IOTHREAD "iothread"
|
||||
|
||||
typedef struct IOThread IOThread;
|
||||
typedef struct {
|
||||
Object parent_obj;
|
||||
|
||||
QemuThread thread;
|
||||
AioContext *ctx;
|
||||
QemuMutex init_done_lock;
|
||||
QemuCond init_done_cond; /* is thread initialization done? */
|
||||
bool stopping;
|
||||
int thread_id;
|
||||
} IOThread;
|
||||
|
||||
#define IOTHREAD(obj) \
|
||||
OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD)
|
||||
|
11
iothread.c
11
iothread.c
@@ -14,7 +14,6 @@
|
||||
#include "qom/object.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "block/aio.h"
|
||||
#include "sysemu/iothread.h"
|
||||
#include "qmp-commands.h"
|
||||
@@ -22,16 +21,6 @@
|
||||
#define IOTHREADS_PATH "/objects"
|
||||
|
||||
typedef ObjectClass IOThreadClass;
|
||||
struct IOThread {
|
||||
Object parent_obj;
|
||||
|
||||
QemuThread thread;
|
||||
AioContext *ctx;
|
||||
QemuMutex init_done_lock;
|
||||
QemuCond init_done_cond; /* is thread initialization done? */
|
||||
bool stopping;
|
||||
int thread_id;
|
||||
};
|
||||
|
||||
#define IOTHREAD_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD)
|
||||
|
@@ -2062,9 +2062,12 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
|
||||
socklen_t addrlen;
|
||||
void *addr;
|
||||
abi_long ret;
|
||||
int host_flags;
|
||||
|
||||
host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
|
||||
|
||||
if (target_addr == 0) {
|
||||
return get_errno(accept4(fd, NULL, NULL, flags));
|
||||
return get_errno(accept4(fd, NULL, NULL, host_flags));
|
||||
}
|
||||
|
||||
/* linux returns EINVAL if addrlen pointer is invalid */
|
||||
@@ -2080,7 +2083,7 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
|
||||
|
||||
addr = alloca(addrlen);
|
||||
|
||||
ret = get_errno(accept4(fd, addr, &addrlen, flags));
|
||||
ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_sockaddr(target_addr, addr, addrlen);
|
||||
if (put_user_u32(addrlen, target_addrlen_addr))
|
||||
|
@@ -1809,6 +1809,7 @@ static ImageInfoList *collect_image_info_list(const char *filename,
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
error_free(err);
|
||||
bdrv_unref(bs);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@@ -569,8 +569,8 @@ static const VMStateDescription vmstate_msr_hypercall_hypercall = {
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
|
||||
VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
|
||||
VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@@ -35,7 +35,7 @@ check-unit-y += tests/test-visitor-serialization$(EXESUF)
|
||||
check-unit-y += tests/test-iov$(EXESUF)
|
||||
gcov-files-test-iov-y = util/iov.c
|
||||
check-unit-y += tests/test-aio$(EXESUF)
|
||||
check-unit-y += tests/test-rfifolock$(EXESUF)
|
||||
check-unit-$(CONFIG_POSIX) += tests/test-rfifolock$(EXESUF)
|
||||
check-unit-y += tests/test-throttle$(EXESUF)
|
||||
gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
|
||||
gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
|
||||
@@ -59,7 +59,7 @@ check-unit-y += tests/test-bitops$(EXESUF)
|
||||
check-unit-y += tests/test-qdev-global-props$(EXESUF)
|
||||
check-unit-y += tests/check-qom-interface$(EXESUF)
|
||||
gcov-files-check-qom-interface-y = qom/object.c
|
||||
check-unit-y += tests/test-vmstate$(EXESUF)
|
||||
check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF)
|
||||
|
||||
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
|
||||
|
||||
@@ -84,6 +84,11 @@ check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
|
||||
gcov-files-virtio-y += hw/virtio/virtio-rng.c
|
||||
check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
|
||||
gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||
check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
|
||||
gcov-files-virtio-y += hw/9pfs/virtio-9p.c
|
||||
gcov-files-virtio-y += i386-softmmu/hw/9pfs/virtio-9p-device.c
|
||||
endif
|
||||
check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
|
||||
gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c
|
||||
check-qtest-virtio-y += $(check-qtest-virtioserial-y)
|
||||
@@ -100,6 +105,8 @@ check-qtest-pci-y += tests/eepro100-test$(EXESUF)
|
||||
gcov-files-pci-y += hw/net/eepro100.c
|
||||
check-qtest-pci-y += tests/ne2000-test$(EXESUF)
|
||||
gcov-files-pci-y += hw/net/ne2000.c
|
||||
check-qtest-pci-y += tests/nvme-test$(EXESUF)
|
||||
gcov-files-pci-y += hw/block/nvme.c
|
||||
check-qtest-pci-y += $(check-qtest-virtio-y)
|
||||
gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c
|
||||
check-qtest-pci-y += tests/tpci200-test$(EXESUF)
|
||||
@@ -126,6 +133,10 @@ check-qtest-i386-y += tests/vmxnet3-test$(EXESUF)
|
||||
gcov-files-i386-y += hw/net/vmxnet3.c
|
||||
gcov-files-i386-y += hw/net/vmxnet_rx_pkt.c
|
||||
gcov-files-i386-y += hw/net/vmxnet_tx_pkt.c
|
||||
check-qtest-i386-y += tests/pvpanic-test$(EXESUF)
|
||||
gcov-files-i386-y += i386-softmmu/hw/misc/pvpanic.c
|
||||
check-qtest-i386-y += tests/i82801b11-test$(EXESUF)
|
||||
gcov-files-i386-y += hw/pci-bridge/i82801b11.c
|
||||
check-qtest-x86_64-y = $(check-qtest-i386-y)
|
||||
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
|
||||
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
|
||||
@@ -265,6 +276,7 @@ tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o
|
||||
tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o
|
||||
tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o
|
||||
tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o
|
||||
tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
|
||||
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
|
||||
tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
|
||||
tests/tpci200-test$(EXESUF): tests/tpci200-test.o
|
||||
@@ -272,13 +284,18 @@ tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
|
||||
tests/qom-test$(EXESUF): tests/qom-test.o
|
||||
tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y)
|
||||
tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
|
||||
tests/nvme-test$(EXESUF): tests/nvme-test.o
|
||||
tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
|
||||
tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
|
||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
||||
|
||||
# QTest rules
|
||||
|
||||
TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
|
||||
check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
|
||||
check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
|
||||
endif
|
||||
|
||||
qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
|
||||
$(check-qtest-y): $(qtest-obj-y)
|
||||
@@ -377,7 +394,8 @@ check-block: $(patsubst %,check-%, $(check-block-y))
|
||||
check: check-qapi-schema check-unit check-qtest
|
||||
check-clean:
|
||||
$(MAKE) -C tests/tcg clean
|
||||
rm -rf $(check-unit-y) $(check-qtest-i386-y) $(check-qtest-x86_64-y) $(check-qtest-sparc64-y) $(check-qtest-sparc-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
|
||||
rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
|
||||
rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y)))
|
||||
|
||||
clean: check-clean
|
||||
|
||||
|
33
tests/i82801b11-test.c
Normal file
33
tests/i82801b11-test.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QTest testcase for i82801b11
|
||||
*
|
||||
* Copyright (c) 2014 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include "libqtest.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
/* Tests only initialization so far. TODO: Replace with functional tests */
|
||||
static void nop(void)
|
||||
{
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/i82801b11/nop", nop);
|
||||
|
||||
qtest_start("-machine q35 -device i82801b11-bridge,bus=pcie.0,addr=1e.0");
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return ret;
|
||||
}
|
@@ -48,6 +48,9 @@ struct QTestState
|
||||
struct sigaction sigact_old; /* restored on exit */
|
||||
};
|
||||
|
||||
static GList *qtest_instances;
|
||||
static struct sigaction sigact_old;
|
||||
|
||||
#define g_assert_no_errno(ret) do { \
|
||||
g_assert_cmpint(ret, !=, -1); \
|
||||
} while (0)
|
||||
@@ -104,7 +107,28 @@ static void kill_qemu(QTestState *s)
|
||||
|
||||
static void sigabrt_handler(int signo)
|
||||
{
|
||||
kill_qemu(global_qtest);
|
||||
GList *elem;
|
||||
for (elem = qtest_instances; elem; elem = elem->next) {
|
||||
kill_qemu(elem->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_sigabrt_handler(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
/* Catch SIGABRT to clean up on g_assert() failure */
|
||||
sigact = (struct sigaction){
|
||||
.sa_handler = sigabrt_handler,
|
||||
.sa_flags = SA_RESETHAND,
|
||||
};
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGABRT, &sigact, &sigact_old);
|
||||
}
|
||||
|
||||
static void cleanup_sigabrt_handler(void)
|
||||
{
|
||||
sigaction(SIGABRT, &sigact_old, NULL);
|
||||
}
|
||||
|
||||
QTestState *qtest_init(const char *extra_args)
|
||||
@@ -115,12 +139,11 @@ QTestState *qtest_init(const char *extra_args)
|
||||
gchar *qmp_socket_path;
|
||||
gchar *command;
|
||||
const char *qemu_binary;
|
||||
struct sigaction sigact;
|
||||
|
||||
qemu_binary = getenv("QTEST_QEMU_BINARY");
|
||||
g_assert(qemu_binary != NULL);
|
||||
|
||||
global_qtest = s = g_malloc(sizeof(*s));
|
||||
s = g_malloc(sizeof(*s));
|
||||
|
||||
socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
|
||||
qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
|
||||
@@ -128,13 +151,12 @@ QTestState *qtest_init(const char *extra_args)
|
||||
sock = init_socket(socket_path);
|
||||
qmpsock = init_socket(qmp_socket_path);
|
||||
|
||||
/* Catch SIGABRT to clean up on g_assert() failure */
|
||||
sigact = (struct sigaction){
|
||||
.sa_handler = sigabrt_handler,
|
||||
.sa_flags = SA_RESETHAND,
|
||||
};
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGABRT, &sigact, &s->sigact_old);
|
||||
/* Only install SIGABRT handler once */
|
||||
if (!qtest_instances) {
|
||||
setup_sigabrt_handler();
|
||||
}
|
||||
|
||||
qtest_instances = g_list_prepend(qtest_instances, s);
|
||||
|
||||
s->qemu_pid = fork();
|
||||
if (s->qemu_pid == 0) {
|
||||
@@ -180,8 +202,12 @@ QTestState *qtest_init(const char *extra_args)
|
||||
|
||||
void qtest_quit(QTestState *s)
|
||||
{
|
||||
sigaction(SIGABRT, &s->sigact_old, NULL);
|
||||
global_qtest = NULL;
|
||||
/* Uninstall SIGABRT handler on last instance */
|
||||
if (qtest_instances && !qtest_instances->next) {
|
||||
cleanup_sigabrt_handler();
|
||||
}
|
||||
|
||||
qtest_instances = g_list_remove(qtest_instances, s);
|
||||
|
||||
kill_qemu(s);
|
||||
close(s->fd);
|
||||
@@ -319,14 +345,10 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens)
|
||||
qmp->response = (QDict *)obj;
|
||||
}
|
||||
|
||||
QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
|
||||
QDict *qtest_qmp_receive(QTestState *s)
|
||||
{
|
||||
QMPResponseParser qmp;
|
||||
|
||||
/* Send QMP request */
|
||||
socket_sendf(s->qmp_fd, fmt, ap);
|
||||
|
||||
/* Receive reply */
|
||||
qmp.response = NULL;
|
||||
json_message_parser_init(&qmp.parser, qmp_response);
|
||||
while (!qmp.response) {
|
||||
@@ -350,6 +372,15 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
|
||||
return qmp.response;
|
||||
}
|
||||
|
||||
QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
|
||||
{
|
||||
/* Send QMP request */
|
||||
socket_sendf(s->qmp_fd, fmt, ap);
|
||||
|
||||
/* Receive reply */
|
||||
return qtest_qmp_receive(s);
|
||||
}
|
||||
|
||||
QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@@ -82,6 +82,14 @@ void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap);
|
||||
*/
|
||||
QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* qtest_receive:
|
||||
* @s: #QTestState instance to operate on.
|
||||
*
|
||||
* Reads a QMP message from QEMU and returns the response.
|
||||
*/
|
||||
QDict *qtest_qmp_receive(QTestState *s);
|
||||
|
||||
/**
|
||||
* qtest_get_irq:
|
||||
* @s: #QTestState instance to operate on.
|
||||
@@ -335,7 +343,8 @@ void qtest_add_func(const char *str, void (*fn));
|
||||
*/
|
||||
static inline QTestState *qtest_start(const char *args)
|
||||
{
|
||||
return qtest_init(args);
|
||||
global_qtest = qtest_init(args);
|
||||
return global_qtest;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,6 +355,7 @@ static inline QTestState *qtest_start(const char *args)
|
||||
static inline void qtest_end(void)
|
||||
{
|
||||
qtest_quit(global_qtest);
|
||||
global_qtest = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,6 +374,16 @@ QDict *qmp(const char *fmt, ...);
|
||||
*/
|
||||
void qmp_discard_response(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* qmp_receive:
|
||||
*
|
||||
* Reads a QMP message from QEMU and returns the response.
|
||||
*/
|
||||
static inline QDict *qmp_receive(void)
|
||||
{
|
||||
return qtest_qmp_receive(global_qtest);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_irq:
|
||||
* @num: Interrupt to observe.
|
||||
|
34
tests/nvme-test.c
Normal file
34
tests/nvme-test.c
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* QTest testcase for NVMe
|
||||
*
|
||||
* Copyright (c) 2014 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include "libqtest.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
/* Tests only initialization so far. TODO: Replace with functional tests */
|
||||
static void nop(void)
|
||||
{
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/nvme/nop", nop);
|
||||
|
||||
qtest_start("-drive id=drv0,if=none,file=/dev/null "
|
||||
"-device nvme,drive=drv0,serial=foo");
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return ret;
|
||||
}
|
47
tests/pvpanic-test.c
Normal file
47
tests/pvpanic-test.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* QTest testcase for PV Panic
|
||||
*
|
||||
* Copyright (c) 2014 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include "libqtest.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
static void test_panic(void)
|
||||
{
|
||||
uint8_t val;
|
||||
QDict *response, *data;
|
||||
|
||||
val = inb(0x505);
|
||||
g_assert_cmpuint(val, ==, 1);
|
||||
|
||||
outb(0x505, 0x1);
|
||||
|
||||
response = qmp_receive();
|
||||
g_assert(qdict_haskey(response, "event"));
|
||||
g_assert_cmpstr(qdict_get_str(response, "event"), ==, "GUEST_PANICKED");
|
||||
g_assert(qdict_haskey(response, "data"));
|
||||
data = qdict_get_qdict(response, "data");
|
||||
g_assert(qdict_haskey(data, "action"));
|
||||
g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/pvpanic/panic", test_panic);
|
||||
|
||||
qtest_start("-device pvpanic");
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return ret;
|
||||
}
|
@@ -475,7 +475,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
|
||||
write failed: No space left on device
|
||||
|
||||
10 leaked clusters were found on the image.
|
||||
11 leaked clusters were found on the image.
|
||||
This means waste of disk space, but no harm to data.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
@@ -499,7 +499,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
|
||||
write failed: No space left on device
|
||||
|
||||
10 leaked clusters were found on the image.
|
||||
11 leaked clusters were found on the image.
|
||||
This means waste of disk space, but no harm to data.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
@@ -523,7 +523,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
|
||||
write failed: No space left on device
|
||||
|
||||
10 leaked clusters were found on the image.
|
||||
11 leaked clusters were found on the image.
|
||||
This means waste of disk space, but no harm to data.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test loading internal snapshots where the L1 table of the snapshot
|
||||
# is smaller than the current L1 table.
|
||||
# qcow2 internal snapshots/VM state tests
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat, Inc.
|
||||
#
|
||||
@@ -31,6 +30,7 @@ status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f $TEST_IMG.snap
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
@@ -45,6 +45,14 @@ _supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
offset_size=24
|
||||
offset_l1_size=36
|
||||
|
||||
echo
|
||||
echo Test loading internal snapshots where the L1 table of the snapshot
|
||||
echo is smaller than the current L1 table.
|
||||
echo
|
||||
|
||||
CLUSTER_SIZE=65536
|
||||
_make_test_img 64M
|
||||
$QEMU_IMG snapshot -c foo "$TEST_IMG"
|
||||
@@ -59,6 +67,32 @@ $QEMU_IO -c 'write -b 0 4M' "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IMG snapshot -a foo "$TEST_IMG"
|
||||
_check_test_img
|
||||
|
||||
|
||||
echo
|
||||
echo Try using a huge VM state
|
||||
echo
|
||||
|
||||
CLUSTER_SIZE=65536
|
||||
_make_test_img 64M
|
||||
{ $QEMU_IO -c "write -b -P 0x11 1T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IMG snapshot -c foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IMG snapshot -a foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IO -c "read -b -P 0x11 1T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
_check_test_img
|
||||
|
||||
|
||||
echo
|
||||
echo "qcow2_snapshot_load_tmp() should take the L1 size from the snapshot"
|
||||
echo
|
||||
|
||||
CLUSTER_SIZE=512
|
||||
_make_test_img 64M
|
||||
{ $QEMU_IMG snapshot -c foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_size" "\x00\x00\x00\x00\x00\x00\x02\x00"
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\x00\x01"
|
||||
{ $QEMU_IMG convert -s foo $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
@@ -1,4 +1,8 @@
|
||||
QA output created by 029
|
||||
|
||||
Test loading internal snapshots where the L1 table of the snapshot
|
||||
is smaller than the current L1 table.
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -7,4 +11,17 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
|
||||
wrote 4194304/4194304 bytes at offset 0
|
||||
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
No errors were found on the image.
|
||||
|
||||
Try using a huge VM state
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 4096/4096 bytes at offset 1099511627776
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 4096/4096 bytes at offset 1099511627776
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
No errors were found on the image.
|
||||
|
||||
qcow2_snapshot_load_tmp() should take the L1 size from the snapshot
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
*** done
|
||||
|
@@ -131,6 +131,26 @@ ulimit -c "$old_ulimit"
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
_check_test_img
|
||||
|
||||
echo
|
||||
echo "== Committing to a backing file with lazy_refcounts=on =="
|
||||
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on"
|
||||
TEST_IMG="$TEST_IMG".base _make_test_img $size
|
||||
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base"
|
||||
_make_test_img $size
|
||||
|
||||
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IMG commit "$TEST_IMG"
|
||||
|
||||
# The dirty bit must not be set
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
./qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
|
||||
|
||||
_check_test_img
|
||||
TEST_IMG="$TEST_IMG".base _check_test_img
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
@@ -54,4 +54,15 @@ wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
|
||||
== Committing to a backing file with lazy_refcounts=on ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Image committed.
|
||||
incompatible_features 0x0
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
No errors were found on the image.
|
||||
*** done
|
||||
|
@@ -1,6 +1,6 @@
|
||||
No errors were found on the image.
|
||||
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
|
||||
Image end offset: 4296448000
|
||||
Image end offset: 4296152064
|
||||
.
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 tests
|
||||
|
@@ -204,6 +204,10 @@ run_qemu -hda foo:bar
|
||||
run_qemu -drive file=foo:bar
|
||||
run_qemu -drive file.filename=foo:bar
|
||||
|
||||
run_qemu -hda "file:$TEST_IMG"
|
||||
run_qemu -drive file="file:$TEST_IMG"
|
||||
run_qemu -drive file.filename="file:$TEST_IMG"
|
||||
|
||||
echo
|
||||
echo === Snapshot mode ===
|
||||
echo
|
||||
@@ -214,6 +218,14 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG"
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on | _filter_qemu_io
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2 -snapshot | _filter_qemu_io
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG" -snapshot | _filter_qemu_io
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG",snapshot=on | _filter_qemu_io
|
||||
|
||||
# Opening a read-only file r/w with snapshot=on
|
||||
chmod u-w "$TEST_IMG"
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io
|
||||
echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
|
||||
chmod u+w "$TEST_IMG"
|
||||
|
||||
$QEMU_IO -c "read -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
|
@@ -275,6 +275,17 @@ QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown proto
|
||||
Testing: -drive file.filename=foo:bar
|
||||
QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory
|
||||
|
||||
Testing: -hda file:TEST_DIR/t.qcow2
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=file:TEST_DIR/t.qcow2
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file.filename=file:TEST_DIR/t.qcow2
|
||||
QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: could not open disk image ide0-hd0: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
|
||||
|
||||
|
||||
=== Snapshot mode ===
|
||||
|
||||
@@ -308,6 +319,34 @@ wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=file:TEST_DIR/t.qcow2 -snapshot
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2 -snapshot
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
read 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off
|
||||
|
106
tests/qemu-iotests/075
Executable file
106
tests/qemu-iotests/075
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# cloop format input validation tests
|
||||
#
|
||||
# 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=stefanha@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 cloop
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
block_size_offset=128
|
||||
n_blocks_offset=132
|
||||
offsets_offset=136
|
||||
|
||||
echo
|
||||
echo "== check that the first sector can be read =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== check that the last sector can be read =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
$QEMU_IO -c "read $((1024 * 1024 - 512)) 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== block_size must be a multiple of 512 =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$block_size_offset" "\x00\x00\x02\x01"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== block_size cannot be zero =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$block_size_offset" "\x00\x00\x00\x00"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== huge block_size ==="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$block_size_offset" "\xff\xff\xfe\x00"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== offsets_size overflow ==="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$n_blocks_offset" "\xff\xff\xff\xff"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== refuse images that require too many offsets ==="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$n_blocks_offset" "\x04\x00\x00\x01"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== refuse images with non-monotonically increasing offsets =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\xff\xff\xff\xff"
|
||||
poke_file "$TEST_IMG" $((offsets_offset + 8)) "\x00\x00\x00\x00\xff\xfe\x00\x00"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== refuse images with invalid compressed block size =="
|
||||
_use_sample_img simple-pattern.cloop.bz2
|
||||
poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
poke_file "$TEST_IMG" $((offsets_offset + 8)) "\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
38
tests/qemu-iotests/075.out
Normal file
38
tests/qemu-iotests/075.out
Normal file
@@ -0,0 +1,38 @@
|
||||
QA output created by 075
|
||||
|
||||
== check that the first sector can be read ==
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== check that the last sector can be read ==
|
||||
read 512/512 bytes at offset 1048064
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== block_size must be a multiple of 512 ==
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size 513 must be a multiple of 512
|
||||
no file open, try 'help open'
|
||||
|
||||
== block_size cannot be zero ==
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size cannot be zero
|
||||
no file open, try 'help open'
|
||||
|
||||
== huge block_size ===
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size 4294966784 must be 64 MB or less
|
||||
no file open, try 'help open'
|
||||
|
||||
== offsets_size overflow ===
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: n_blocks 4294967295 must be 536870911 or less
|
||||
no file open, try 'help open'
|
||||
|
||||
== refuse images that require too many offsets ===
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: image requires too many offsets, try increasing block size
|
||||
no file open, try 'help open'
|
||||
|
||||
== refuse images with non-monotonically increasing offsets ==
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: offsets not monotonically increasing at index 1, image file is corrupt
|
||||
no file open, try 'help open'
|
||||
|
||||
== refuse images with invalid compressed block size ==
|
||||
qemu-io: can't open device TEST_DIR/simple-pattern.cloop: invalid compressed block size at index 1, image file is corrupt
|
||||
no file open, try 'help open'
|
||||
*** done
|
76
tests/qemu-iotests/076
Executable file
76
tests/qemu-iotests/076
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# parallels format input validation tests
|
||||
#
|
||||
# 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 parallels
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
tracks_offset=$((0x1c))
|
||||
catalog_entries_offset=$((0x20))
|
||||
nb_sectors_offset=$((0x24))
|
||||
|
||||
echo
|
||||
echo "== Read from a valid (enough) image =="
|
||||
_use_sample_img fake.parallels.bz2
|
||||
{ $QEMU_IO -c "read -P 0x11 0 64k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Negative catalog size =="
|
||||
_use_sample_img fake.parallels.bz2
|
||||
poke_file "$TEST_IMG" "$catalog_entries_offset" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Overflow in catalog allocation =="
|
||||
_use_sample_img fake.parallels.bz2
|
||||
poke_file "$TEST_IMG" "$nb_sectors_offset" "\xff\xff\xff\xff"
|
||||
poke_file "$TEST_IMG" "$catalog_entries_offset" "\x01\x00\x00\x40"
|
||||
{ $QEMU_IO -c "read 64M 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Zero sectors per track =="
|
||||
_use_sample_img fake.parallels.bz2
|
||||
poke_file "$TEST_IMG" "$tracks_offset" "\x00\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
18
tests/qemu-iotests/076.out
Normal file
18
tests/qemu-iotests/076.out
Normal file
@@ -0,0 +1,18 @@
|
||||
QA output created by 076
|
||||
|
||||
== Read from a valid (enough) image ==
|
||||
read 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Negative catalog size ==
|
||||
qemu-io: can't open device TEST_DIR/fake.parallels: Catalog too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Overflow in catalog allocation ==
|
||||
qemu-io: can't open device TEST_DIR/fake.parallels: Catalog too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Zero sectors per track ==
|
||||
qemu-io: can't open device TEST_DIR/fake.parallels: Invalid image: Zero sectors per track
|
||||
no file open, try 'help open'
|
||||
*** done
|
87
tests/qemu-iotests/078
Executable file
87
tests/qemu-iotests/078
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# bochs format input validation tests
|
||||
#
|
||||
# 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 bochs
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
catalog_size_offset=$((0x48))
|
||||
extent_size_offset=$((0x50))
|
||||
disk_size_offset=$((0x58))
|
||||
|
||||
echo
|
||||
echo "== Read from a valid image =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Negative catalog size =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$catalog_size_offset" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Overflow for catalog size * sizeof(uint32_t) =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$catalog_size_offset" "\x00\x00\x00\x40"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Too small catalog bitmap for image size =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$disk_size_offset" "\x00\xc0\x0f\x00\x00\x00\x00\x7f"
|
||||
{ $QEMU_IO -c "read 2T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Negative extent size =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$extent_size_offset" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 768k 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Zero extent size =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$extent_size_offset" "\x00\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
26
tests/qemu-iotests/078.out
Normal file
26
tests/qemu-iotests/078.out
Normal file
@@ -0,0 +1,26 @@
|
||||
QA output created by 078
|
||||
|
||||
== Read from a valid image ==
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Negative catalog size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Overflow for catalog size * sizeof(uint32_t) ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Too small catalog bitmap for image size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size
|
||||
no file open, try 'help open'
|
||||
|
||||
== Negative extent size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size 4294967295 is too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Zero extent size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size may not be zero
|
||||
no file open, try 'help open'
|
||||
*** done
|
180
tests/qemu-iotests/080
Executable file
180
tests/qemu-iotests/080
Executable file
@@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# qcow2 format input validation tests
|
||||
#
|
||||
# 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()
|
||||
{
|
||||
rm -f $TEST_IMG.snap
|
||||
_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
|
||||
|
||||
header_size=104
|
||||
|
||||
offset_backing_file_offset=8
|
||||
offset_backing_file_size=16
|
||||
offset_l1_size=36
|
||||
offset_l1_table_offset=40
|
||||
offset_refcount_table_offset=48
|
||||
offset_refcount_table_clusters=56
|
||||
offset_nb_snapshots=60
|
||||
offset_snapshots_offset=64
|
||||
offset_header_size=100
|
||||
offset_ext_magic=$header_size
|
||||
offset_ext_size=$((header_size + 4))
|
||||
|
||||
offset_l2_table_0=$((0x40000))
|
||||
|
||||
offset_snap1=$((0x70000))
|
||||
offset_snap1_l1_offset=$((offset_snap1 + 0))
|
||||
offset_snap1_l1_size=$((offset_snap1 + 8))
|
||||
|
||||
echo
|
||||
echo "== Huge header size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_header_size" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_header_size" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Huge unknown header extension =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
poke_file "$TEST_IMG" "$offset_ext_magic" "\x12\x34\x56\x78"
|
||||
poke_file "$TEST_IMG" "$offset_ext_size" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Huge refcount table size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x02\x00\x01"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Misaligned refcount table =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\x12\x34\x56\x78\x90\xab\xcd\xef"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Huge refcount offset =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\xff\xff\xff\xff\xff\xff\x00\x00"
|
||||
poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x00\x00\x7f"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid snapshot table =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_nb_snapshots" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_nb_snapshots" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
poke_file "$TEST_IMG" "$offset_snapshots_offset" "\xff\xff\xff\xff\xff\xff\x00\x00"
|
||||
poke_file "$TEST_IMG" "$offset_nb_snapshots" "\x00\x00\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
poke_file "$TEST_IMG" "$offset_snapshots_offset" "\x12\x34\x56\x78\x90\xab\xcd\xef"
|
||||
poke_file "$TEST_IMG" "$offset_nb_snapshots" "\x00\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Hitting snapshot table size limit =="
|
||||
_make_test_img 64M
|
||||
# Put the refcount table in a more or less safe place (16 MB)
|
||||
poke_file "$TEST_IMG" "$offset_snapshots_offset" "\x00\x00\x00\x00\x01\x00\x00\x00"
|
||||
poke_file "$TEST_IMG" "$offset_nb_snapshots" "\x00\x01\x00\x00"
|
||||
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid L1 table =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
poke_file "$TEST_IMG" "$offset_l1_table_offset" "\x7f\xff\xff\xff\xff\xff\x00\x00"
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
poke_file "$TEST_IMG" "$offset_l1_table_offset" "\x12\x34\x56\x78\x90\xab\xcd\xef"
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\x00\x01"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid L1 table (with internal snapshot in the image) =="
|
||||
_make_test_img 64M
|
||||
{ $QEMU_IMG snapshot -c foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\x00\x00"
|
||||
_img_info
|
||||
|
||||
echo
|
||||
echo "== Invalid backing file size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x10\x00"
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid L2 entry (huge physical offset) =="
|
||||
_make_test_img 64M
|
||||
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_table_0" "\xbf\xff\xff\xff\xff\xff\x00\x00"
|
||||
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_table_0" "\x80\x00\x00\xff\xff\xff\x00\x00"
|
||||
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid snapshot L1 table =="
|
||||
_make_test_img 64M
|
||||
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IMG snapshot -c test $TEST_IMG; } 2>&1 | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_snap1_l1_size" "\x10\x00\x00\x00"
|
||||
{ $QEMU_IMG convert -s test $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
83
tests/qemu-iotests/080.out
Normal file
83
tests/qemu-iotests/080.out
Normal file
@@ -0,0 +1,83 @@
|
||||
QA output created by 080
|
||||
|
||||
== Huge header size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size
|
||||
no file open, try 'help open'
|
||||
|
||||
== Huge unknown header extension ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid backing file offset
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Huge refcount table size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Misaligned refcount table ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
|
||||
no file open, try 'help open'
|
||||
|
||||
== Huge refcount offset ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid snapshot table ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Too many snapshots
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Too many snapshots
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset
|
||||
no file open, try 'help open'
|
||||
|
||||
== Hitting snapshot table size limit ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-img: Could not create snapshot 'test': -27 (File too large)
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Invalid L1 table ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Active L1 table too large
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Active L1 table too large
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid L1 table (with internal snapshot in the image) ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': L1 table is too small
|
||||
|
||||
== Invalid backing file size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow2: Backing file name too long
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid L2 entry (huge physical offset) ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
qemu-img: Could not create snapshot 'test': -27 (File too large)
|
||||
qemu-img: Could not create snapshot 'test': -11 (Resource temporarily unavailable)
|
||||
|
||||
== Invalid snapshot L1 table ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
qemu-img: Failed to load snapshot: Snapshot L1 table too large
|
||||
*** done
|
104
tests/qemu-iotests/084
Executable file
104
tests/qemu-iotests/084
Executable file
@@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for VDI header corruption; image too large, and too many blocks
|
||||
#
|
||||
# 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=jcody@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
|
||||
|
||||
# This tests vdi-specific header fields
|
||||
_supported_fmt vdi
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
ds_offset=368 # disk image size field offset
|
||||
bs_offset=376 # block size field offset
|
||||
bii_offset=384 # block in image field offset
|
||||
|
||||
echo
|
||||
echo "=== Testing image size bounds ==="
|
||||
echo
|
||||
_make_test_img 64M
|
||||
|
||||
# check for image size too large
|
||||
# poke max image size, and appropriate blocks_in_image value
|
||||
echo "Test 1: Maximum size (1024 TB):"
|
||||
poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\xf0\xff\xff\xff\x03\x00"
|
||||
poke_file "$TEST_IMG" "$bii_offset" "\xff\xff\xff\x3f"
|
||||
_img_info
|
||||
|
||||
echo
|
||||
echo "Test 2: Size too large (1024TB + 1)"
|
||||
# This should be too large (-EINVAL):
|
||||
poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\xf1\xff\xff\xff\x03\x00"
|
||||
_img_info
|
||||
|
||||
echo
|
||||
echo "Test 3: Size valid (64M), but Blocks In Image too small (63)"
|
||||
# This sets the size to 64M, but with a blocks_in_image size that is
|
||||
# too small
|
||||
poke_file "$TEST_IMG" "$ds_offset" "\x00\x00\x00\x04\x00\x00\x00\x00"
|
||||
# For a 64M image, we would need a blocks_in_image value of at least 64,
|
||||
# so 63 should be too small and give us -ENOTSUP
|
||||
poke_file "$TEST_IMG" "$bii_offset" "\x3f\x00\x00\x00"
|
||||
_img_info
|
||||
|
||||
echo
|
||||
echo "Test 4: Size valid (64M), but Blocks In Image exceeds max allowed"
|
||||
# Now check the bounds of blocks_in_image - 0x3fffffff should be the max
|
||||
# value here, and we should get -ENOTSUP
|
||||
poke_file "$TEST_IMG" "$bii_offset" "\x00\x00\x00\x40"
|
||||
_img_info
|
||||
|
||||
# Finally, 1MB is the only block size supported. Verify that
|
||||
# a value != 1MB results in error, both smaller and larger
|
||||
echo
|
||||
echo "Test 5: Valid Image: 64MB, Blocks In Image 64, Block Size 1MB"
|
||||
poke_file "$TEST_IMG" "$bii_offset" "\x40\x00\x00\x00" # reset bii to valid
|
||||
poke_file "$TEST_IMG" "$bs_offset" "\x00\x00\x10\x00" # valid
|
||||
_img_info
|
||||
echo
|
||||
echo "Test 6: Block Size != 1MB; too small test (1MB - 1)"
|
||||
poke_file "$TEST_IMG" "$bs_offset" "\xff\xff\x0f\x00" # invalid (too small)
|
||||
_img_info
|
||||
echo
|
||||
echo "Test 7: Block Size != 1MB; too large test (1MB + 64KB)"
|
||||
poke_file "$TEST_IMG" "$bs_offset" "\x00\x00\x11\x00" # invalid (too large)
|
||||
_img_info
|
||||
# success, all done
|
||||
echo
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
33
tests/qemu-iotests/084.out
Normal file
33
tests/qemu-iotests/084.out
Normal file
@@ -0,0 +1,33 @@
|
||||
QA output created by 084
|
||||
|
||||
=== Testing image size bounds ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
Test 1: Maximum size (1024 TB):
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 1024T (1125899905794048 bytes)
|
||||
cluster_size: 1048576
|
||||
|
||||
Test 2: Size too large (1024TB + 1)
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported VDI image size (size is 0x3fffffff10000, max supported is 0x3fffffff00000)
|
||||
|
||||
Test 3: Size valid (64M), but Blocks In Image too small (63)
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (disk size 67108864, image bitmap has room for 66060288)
|
||||
|
||||
Test 4: Size valid (64M), but Blocks In Image exceeds max allowed
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (too many blocks 1073741824, max is 1073741823)
|
||||
|
||||
Test 5: Valid Image: 64MB, Blocks In Image 64, Block Size 1MB
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
cluster_size: 1048576
|
||||
|
||||
Test 6: Block Size != 1MB; too small test (1MB - 1)
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (block size 1048575 is not 1048576)
|
||||
|
||||
Test 7: Block Size != 1MB; too large test (1MB + 64KB)
|
||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': unsupported VDI image (block size 1114112 is not 1048576)
|
||||
|
||||
*** done
|
64
tests/qemu-iotests/088
Executable file
64
tests/qemu-iotests/088
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# vpc (VHD) format input validation tests
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=kwolf@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f $TEST_IMG.snap
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt vpc
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
offset_block_size=$((512 + 32))
|
||||
|
||||
echo
|
||||
echo "== Invalid block size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_block_size" "\x00\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_block_size" "\x00\x00\x00\x80"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_block_size" "\x12\x34\x56\x78"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
{ $QEMU_IO -c "write 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
17
tests/qemu-iotests/088.out
Normal file
17
tests/qemu-iotests/088.out
Normal file
@@ -0,0 +1,17 @@
|
||||
QA output created by 088
|
||||
|
||||
== Invalid block size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 0
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 0
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 128
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 128
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 305419896
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 305419896
|
||||
no file open, try 'help open'
|
||||
*** done
|
@@ -136,7 +136,10 @@ common options
|
||||
|
||||
check options
|
||||
-raw test raw (default)
|
||||
-bochs test bochs
|
||||
-cow test cow
|
||||
-cloop test cloop
|
||||
-parallels test parallels
|
||||
-qcow test qcow
|
||||
-qcow2 test qcow2
|
||||
-qed test qed
|
||||
@@ -173,11 +176,29 @@ testlist options
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-bochs)
|
||||
IMGFMT=bochs
|
||||
IMGFMT_GENERIC=false
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-cow)
|
||||
IMGFMT=cow
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-cloop)
|
||||
IMGFMT=cloop
|
||||
IMGFMT_GENERIC=false
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-parallels)
|
||||
IMGFMT=parallels
|
||||
IMGFMT_GENERIC=false
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-qcow)
|
||||
IMGFMT=qcow
|
||||
xpand=false
|
||||
|
@@ -364,6 +364,9 @@ _fail()
|
||||
#
|
||||
_supported_fmt()
|
||||
{
|
||||
# "generic" is suitable for most image formats. For some formats it doesn't
|
||||
# work, however (most notably read-only formats), so they can opt out by
|
||||
# setting IMGFMT_GENERIC to false.
|
||||
for f; do
|
||||
if [ "$f" = "$IMGFMT" -o "$f" = "generic" -a "$IMGFMT_GENERIC" = "true" ]; then
|
||||
return
|
||||
|
@@ -81,11 +81,17 @@
|
||||
072 rw auto quick
|
||||
073 rw auto quick
|
||||
074 rw auto quick
|
||||
075 rw auto
|
||||
076 auto
|
||||
077 rw auto quick
|
||||
078 rw auto
|
||||
079 rw auto
|
||||
080 rw auto
|
||||
081 rw auto
|
||||
082 rw auto quick
|
||||
083 rw auto
|
||||
084 img auto
|
||||
085 rw auto
|
||||
086 rw auto quick
|
||||
087 rw auto
|
||||
088 rw auto
|
||||
|
BIN
tests/qemu-iotests/sample_images/empty.bochs.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/empty.bochs.bz2
Normal file
Binary file not shown.
BIN
tests/qemu-iotests/sample_images/fake.parallels.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/fake.parallels.bz2
Normal file
Binary file not shown.
BIN
tests/qemu-iotests/sample_images/simple-pattern.cloop.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/simple-pattern.cloop.bz2
Normal file
Binary file not shown.
@@ -65,6 +65,8 @@ static void bh_test_cb(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
static void timer_test_cb(void *opaque)
|
||||
{
|
||||
TimerTestData *data = opaque;
|
||||
@@ -78,6 +80,8 @@ static void dummy_io_handler_read(void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
static void bh_delete_cb(void *opaque)
|
||||
{
|
||||
BHTestData *data = opaque;
|
||||
@@ -423,6 +427,8 @@ static void test_wait_event_notifier_noflush(void)
|
||||
event_notifier_cleanup(&data.e);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
static void test_timer_schedule(void)
|
||||
{
|
||||
TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL,
|
||||
@@ -484,6 +490,8 @@ static void test_timer_schedule(void)
|
||||
timer_del(&data.timer);
|
||||
}
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
/* Now the same tests, using the context as a GSource. They are
|
||||
* very similar to the ones above, with g_main_context_iteration
|
||||
* replacing aio_poll. However:
|
||||
@@ -766,6 +774,8 @@ static void test_source_wait_event_notifier_noflush(void)
|
||||
event_notifier_cleanup(&data.e);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
static void test_source_timer_schedule(void)
|
||||
{
|
||||
TimerTestData data = { .n = 0, .ctx = ctx, .ns = SCALE_MS * 750LL,
|
||||
@@ -815,6 +825,8 @@ static void test_source_timer_schedule(void)
|
||||
timer_del(&data.timer);
|
||||
}
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
|
||||
/* End of tests. */
|
||||
|
||||
@@ -845,7 +857,9 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/aio/event/wait", test_wait_event_notifier);
|
||||
g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush);
|
||||
g_test_add_func("/aio/event/flush", test_flush_event_notifier);
|
||||
#if !defined(_WIN32)
|
||||
g_test_add_func("/aio/timer/schedule", test_timer_schedule);
|
||||
#endif
|
||||
|
||||
g_test_add_func("/aio-gsource/notify", test_source_notify);
|
||||
g_test_add_func("/aio-gsource/flush", test_source_flush);
|
||||
@@ -860,6 +874,8 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/aio-gsource/event/wait", test_source_wait_event_notifier);
|
||||
g_test_add_func("/aio-gsource/event/wait/no-flush-cb", test_source_wait_event_notifier_noflush);
|
||||
g_test_add_func("/aio-gsource/event/flush", test_source_flush_event_notifier);
|
||||
#if !defined(_WIN32)
|
||||
g_test_add_func("/aio-gsource/timer/schedule", test_source_timer_schedule);
|
||||
#endif
|
||||
return g_test_run();
|
||||
}
|
||||
|
@@ -15,42 +15,133 @@
|
||||
|
||||
#define OMAP2_I2C_1_BASE 0x48070000
|
||||
|
||||
#define N8X0_ADDR 0x48
|
||||
#define TMP105_TEST_ID "tmp105-test"
|
||||
#define TMP105_TEST_ADDR 0x49
|
||||
|
||||
static I2CAdapter *i2c;
|
||||
static uint8_t addr;
|
||||
|
||||
static void send_and_receive(void)
|
||||
static uint16_t tmp105_get8(I2CAdapter *i2c, uint8_t addr, uint8_t reg)
|
||||
{
|
||||
uint8_t resp[1];
|
||||
i2c_send(i2c, addr, ®, 1);
|
||||
i2c_recv(i2c, addr, resp, 1);
|
||||
return resp[0];
|
||||
}
|
||||
|
||||
static uint16_t tmp105_get16(I2CAdapter *i2c, uint8_t addr, uint8_t reg)
|
||||
{
|
||||
uint8_t resp[2];
|
||||
i2c_send(i2c, addr, ®, 1);
|
||||
i2c_recv(i2c, addr, resp, 2);
|
||||
return (resp[0] << 8) | resp[1];
|
||||
}
|
||||
|
||||
static void tmp105_set8(I2CAdapter *i2c, uint8_t addr, uint8_t reg,
|
||||
uint8_t value)
|
||||
{
|
||||
uint8_t cmd[2];
|
||||
uint8_t resp[1];
|
||||
|
||||
cmd[0] = reg;
|
||||
cmd[1] = value;
|
||||
i2c_send(i2c, addr, cmd, 2);
|
||||
i2c_recv(i2c, addr, resp, 1);
|
||||
g_assert_cmphex(resp[0], ==, cmd[1]);
|
||||
}
|
||||
|
||||
static void tmp105_set16(I2CAdapter *i2c, uint8_t addr, uint8_t reg,
|
||||
uint16_t value)
|
||||
{
|
||||
uint8_t cmd[3];
|
||||
uint8_t resp[2];
|
||||
|
||||
cmd[0] = TMP105_REG_TEMPERATURE;
|
||||
i2c_send(i2c, addr, cmd, 1);
|
||||
i2c_recv(i2c, addr, resp, 2);
|
||||
g_assert_cmpuint(((uint16_t)resp[0] << 8) | resp[1], ==, 0);
|
||||
|
||||
cmd[0] = TMP105_REG_CONFIG;
|
||||
cmd[1] = 0x0; /* matches the reset value */
|
||||
i2c_send(i2c, addr, cmd, 2);
|
||||
i2c_recv(i2c, addr, resp, 1);
|
||||
g_assert_cmphex(resp[0], ==, cmd[1]);
|
||||
|
||||
cmd[0] = TMP105_REG_T_LOW;
|
||||
cmd[1] = 0x12;
|
||||
cmd[2] = 0x34;
|
||||
cmd[0] = reg;
|
||||
cmd[1] = value >> 8;
|
||||
cmd[2] = value & 255;
|
||||
i2c_send(i2c, addr, cmd, 3);
|
||||
i2c_recv(i2c, addr, resp, 2);
|
||||
g_assert_cmphex(resp[0], ==, cmd[1]);
|
||||
g_assert_cmphex(resp[1], ==, cmd[2]);
|
||||
}
|
||||
|
||||
cmd[0] = TMP105_REG_T_HIGH;
|
||||
cmd[1] = 0x42;
|
||||
cmd[2] = 0x31;
|
||||
i2c_send(i2c, addr, cmd, 3);
|
||||
i2c_recv(i2c, addr, resp, 2);
|
||||
g_assert_cmphex(resp[0], ==, cmd[1]);
|
||||
g_assert_cmphex(resp[1], ==, cmd[2]);
|
||||
static int qmp_tmp105_get_temperature(const char *id)
|
||||
{
|
||||
QDict *response;
|
||||
int ret;
|
||||
|
||||
response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', "
|
||||
"'property': 'temperature' } }", id);
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
ret = qdict_get_int(response, "return");
|
||||
QDECREF(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qmp_tmp105_set_temperature(const char *id, int value)
|
||||
{
|
||||
QDict *response;
|
||||
|
||||
response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', "
|
||||
"'property': 'temperature', 'value': %d } }", id, value);
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
QDECREF(response);
|
||||
}
|
||||
|
||||
#define TMP105_PRECISION (1000/16)
|
||||
static void send_and_receive(void)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
|
||||
g_assert_cmpuint(value, ==, 0);
|
||||
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0);
|
||||
|
||||
qmp_tmp105_set_temperature(TMP105_TEST_ID, 20000);
|
||||
value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
|
||||
g_assert_cmpuint(value, ==, 20000);
|
||||
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x1400);
|
||||
|
||||
qmp_tmp105_set_temperature(TMP105_TEST_ID, 20938); /* 20 + 15/16 */
|
||||
value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
|
||||
g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
|
||||
g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
|
||||
|
||||
/* Set config */
|
||||
tmp105_set8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG, 0x60);
|
||||
value = tmp105_get8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG);
|
||||
g_assert_cmphex(value, ==, 0x60);
|
||||
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x14f0);
|
||||
|
||||
/* Set precision to 9, 10, 11 bits. */
|
||||
tmp105_set8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG, 0x00);
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x1480);
|
||||
|
||||
tmp105_set8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG, 0x20);
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x14c0);
|
||||
|
||||
tmp105_set8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG, 0x40);
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x14e0);
|
||||
|
||||
/* stored precision remains the same */
|
||||
value = qmp_tmp105_get_temperature(TMP105_TEST_ID);
|
||||
g_assert_cmpuint(value, >=, 20938 - TMP105_PRECISION/2);
|
||||
g_assert_cmpuint(value, <, 20938 + TMP105_PRECISION/2);
|
||||
|
||||
tmp105_set8(i2c, TMP105_TEST_ADDR, TMP105_REG_CONFIG, 0x60);
|
||||
value = tmp105_get16(i2c, TMP105_TEST_ADDR, TMP105_REG_TEMPERATURE);
|
||||
g_assert_cmphex(value, ==, 0x14f0);
|
||||
|
||||
tmp105_set16(i2c, TMP105_TEST_ADDR, TMP105_REG_T_LOW, 0x1234);
|
||||
tmp105_set16(i2c, TMP105_TEST_ADDR, TMP105_REG_T_HIGH, 0x4231);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -60,9 +151,10 @@ int main(int argc, char **argv)
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
s = qtest_start("-machine n800");
|
||||
s = qtest_start("-machine n800 "
|
||||
"-device tmp105,bus=i2c-bus.0,id=" TMP105_TEST_ID
|
||||
",address=0x49");
|
||||
i2c = omap_i2c_create(OMAP2_I2C_1_BASE);
|
||||
addr = N8X0_ADDR;
|
||||
|
||||
qtest_add_func("/tmp105/tx-rx", send_and_receive);
|
||||
|
||||
|
46
tests/virtio-9p-test.c
Normal file
46
tests/virtio-9p-test.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* QTest testcase for VirtIO 9P
|
||||
*
|
||||
* Copyright (c) 2014 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "libqtest.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
/* Tests only initialization so far. TODO: Replace with functional tests */
|
||||
static void pci_nop(void)
|
||||
{
|
||||
}
|
||||
|
||||
static char test_share[] = "/tmp/qtest.XXXXXX";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *args;
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/virtio/9p/pci/nop", pci_nop);
|
||||
|
||||
g_assert(mkdtemp(test_share));
|
||||
|
||||
args = g_strdup_printf("-fsdev local,id=fsdev0,security_model=none,path=%s "
|
||||
"-device virtio-9p-pci,fsdev=fsdev0,mount_tag=qtest",
|
||||
test_share);
|
||||
qtest_start(args);
|
||||
g_free(args);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
rmdir(test_share);
|
||||
|
||||
return ret;
|
||||
}
|
@@ -1777,7 +1777,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
55
ui/gtk.c
55
ui/gtk.c
@@ -156,8 +156,11 @@ typedef struct GtkDisplayState
|
||||
DisplayChangeListener dcl;
|
||||
DisplaySurface *ds;
|
||||
int button_mask;
|
||||
gboolean last_set;
|
||||
int last_x;
|
||||
int last_y;
|
||||
int grab_x_root;
|
||||
int grab_y_root;
|
||||
|
||||
double scale_x;
|
||||
double scale_y;
|
||||
@@ -473,9 +476,16 @@ static void gd_change_runstate(void *opaque, int running, RunState state)
|
||||
|
||||
static void gd_mouse_mode_change(Notifier *notify, void *data)
|
||||
{
|
||||
gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
|
||||
GtkDisplayState *s;
|
||||
|
||||
s = container_of(notify, GtkDisplayState, mouse_mode_notifier);
|
||||
/* release the grab at switching to absolute mode */
|
||||
if (qemu_input_is_absolute() && gd_is_grab_active(s)) {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
|
||||
FALSE);
|
||||
}
|
||||
gd_update_cursor(s, FALSE);
|
||||
}
|
||||
|
||||
/** GTK Events **/
|
||||
|
||||
@@ -616,25 +626,25 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
|
||||
x = (motion->x - mx) / s->scale_x;
|
||||
y = (motion->y - my) / s->scale_y;
|
||||
|
||||
if (qemu_input_is_absolute()) {
|
||||
if (x < 0 || y < 0 ||
|
||||
x >= surface_width(s->ds) ||
|
||||
y >= surface_height(s->ds)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (qemu_input_is_absolute()) {
|
||||
qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x,
|
||||
surface_width(s->ds));
|
||||
qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y,
|
||||
surface_height(s->ds));
|
||||
qemu_input_event_sync();
|
||||
} else if (s->last_x != -1 && s->last_y != -1 && gd_is_grab_active(s)) {
|
||||
} else if (s->last_set && gd_is_grab_active(s)) {
|
||||
qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x);
|
||||
qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y);
|
||||
qemu_input_event_sync();
|
||||
}
|
||||
s->last_x = x;
|
||||
s->last_y = y;
|
||||
s->last_set = TRUE;
|
||||
|
||||
if (!qemu_input_is_absolute() && gd_is_grab_active(s)) {
|
||||
GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
|
||||
@@ -669,8 +679,7 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
|
||||
GdkDisplay *display = gtk_widget_get_display(widget);
|
||||
gdk_display_warp_pointer(display, screen, x, y);
|
||||
#endif
|
||||
s->last_x = -1;
|
||||
s->last_y = -1;
|
||||
s->last_set = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -683,6 +692,14 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
|
||||
GtkDisplayState *s = opaque;
|
||||
InputButton btn;
|
||||
|
||||
/* implicitly grab the input at the first click in the relative mode */
|
||||
if (button->button == 1 && button->type == GDK_BUTTON_PRESS &&
|
||||
!qemu_input_is_absolute() && !gd_is_grab_active(s)) {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
|
||||
TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (button->button == 1) {
|
||||
btn = INPUT_BUTTON_LEFT;
|
||||
} else if (button->button == 2) {
|
||||
@@ -765,6 +782,14 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean gd_event(GtkWidget *widget, GdkEvent *event, void *opaque)
|
||||
{
|
||||
if (event->type == GDK_MOTION_NOTIFY) {
|
||||
return gd_motion_event(widget, &event->motion, opaque);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** Window Menu Actions **/
|
||||
|
||||
static void gd_menu_pause(GtkMenuItem *item, void *opaque)
|
||||
@@ -963,8 +988,8 @@ static void gd_ungrab_keyboard(GtkDisplayState *s)
|
||||
|
||||
static void gd_grab_pointer(GtkDisplayState *s)
|
||||
{
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
|
||||
GList *devices = gdk_device_manager_list_devices(mgr,
|
||||
GDK_DEVICE_TYPE_MASTER);
|
||||
@@ -988,6 +1013,8 @@ static void gd_grab_pointer(GtkDisplayState *s)
|
||||
tmp = tmp->next;
|
||||
}
|
||||
g_list_free(devices);
|
||||
gdk_device_get_position(gdk_device_manager_get_client_pointer(mgr),
|
||||
NULL, &s->grab_x_root, &s->grab_y_root);
|
||||
#else
|
||||
gdk_pointer_grab(gtk_widget_get_window(s->drawing_area),
|
||||
FALSE, /* All events to come to our window directly */
|
||||
@@ -999,13 +1026,15 @@ static void gd_grab_pointer(GtkDisplayState *s)
|
||||
NULL, /* Allow cursor to move over entire desktop */
|
||||
s->null_cursor,
|
||||
GDK_CURRENT_TIME);
|
||||
gdk_display_get_pointer(display, NULL,
|
||||
&s->grab_x_root, &s->grab_y_root, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gd_ungrab_pointer(GtkDisplayState *s)
|
||||
{
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
|
||||
GList *devices = gdk_device_manager_list_devices(mgr,
|
||||
GDK_DEVICE_TYPE_MASTER);
|
||||
@@ -1019,8 +1048,14 @@ static void gd_ungrab_pointer(GtkDisplayState *s)
|
||||
tmp = tmp->next;
|
||||
}
|
||||
g_list_free(devices);
|
||||
gdk_device_warp(gdk_device_manager_get_client_pointer(mgr),
|
||||
gtk_widget_get_screen(s->drawing_area),
|
||||
s->grab_x_root, s->grab_y_root);
|
||||
#else
|
||||
gdk_pointer_ungrab(GDK_CURRENT_TIME);
|
||||
gdk_display_warp_pointer(display,
|
||||
gtk_widget_get_screen(s->drawing_area),
|
||||
s->grab_x_root, s->grab_y_root);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1267,8 +1302,8 @@ static void gd_connect_signals(GtkDisplayState *s)
|
||||
g_signal_connect(s->drawing_area, "expose-event",
|
||||
G_CALLBACK(gd_expose_event), s);
|
||||
#endif
|
||||
g_signal_connect(s->drawing_area, "motion-notify-event",
|
||||
G_CALLBACK(gd_motion_event), s);
|
||||
g_signal_connect(s->drawing_area, "event",
|
||||
G_CALLBACK(gd_event), s);
|
||||
g_signal_connect(s->drawing_area, "button-press-event",
|
||||
G_CALLBACK(gd_button_event), s);
|
||||
g_signal_connect(s->drawing_area, "button-release-event",
|
||||
|
@@ -549,6 +549,10 @@ static int interface_client_monitors_config(QXLInstance *sin,
|
||||
QemuUIInfo info;
|
||||
int rc;
|
||||
|
||||
if (!mc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: multihead is tricky due to the way
|
||||
* spice has multihead implemented.
|
||||
|
Reference in New Issue
Block a user