diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/Makefile.include | 2 | ||||
| -rw-r--r-- | tests/cpu-plug-test.c | 2 | ||||
| -rw-r--r-- | tests/fw_cfg-test.c | 21 | ||||
| -rw-r--r-- | tests/image-fuzzer/qcow2/__init__.py | 1 | ||||
| -rw-r--r-- | tests/image-fuzzer/qcow2/fuzz.py | 54 | ||||
| -rw-r--r-- | tests/image-fuzzer/qcow2/layout.py | 57 | ||||
| -rwxr-xr-x | tests/image-fuzzer/runner.py | 16 | ||||
| -rw-r--r-- | tests/libqtest.c | 1 | ||||
| -rw-r--r-- | tests/migration-test.c | 9 | ||||
| -rw-r--r-- | tests/plugin/bb.c | 2 | ||||
| -rw-r--r-- | tests/plugin/empty.c | 2 | ||||
| -rw-r--r-- | tests/plugin/hotblocks.c | 2 | ||||
| -rw-r--r-- | tests/plugin/hotpages.c | 2 | ||||
| -rw-r--r-- | tests/plugin/howvec.c | 2 | ||||
| -rw-r--r-- | tests/plugin/insn.c | 2 | ||||
| -rw-r--r-- | tests/plugin/mem.c | 2 | ||||
| -rwxr-xr-x | tests/qemu-iotests/272 | 79 | ||||
| -rw-r--r-- | tests/qemu-iotests/272.out | 10 | ||||
| -rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
| -rw-r--r-- | tests/tcg/multiarch/linux-test.c | 3 | ||||
| -rwxr-xr-x | tests/vm/basevm.py | 29 | ||||
| -rwxr-xr-x | tests/vm/netbsd | 188 |
22 files changed, 407 insertions, 80 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include index 534ee48743..8566f5f119 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -177,7 +177,9 @@ check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF) check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF) +ifdef CONFIG_LINUX check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF) +endif check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/device-plug-test$(EXESUF) diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c index 058cef5ac1..30e514bbfb 100644 --- a/tests/cpu-plug-test.c +++ b/tests/cpu-plug-test.c @@ -99,6 +99,7 @@ static void test_plug_with_device_add(gconstpointer data) cpu = qobject_to(QDict, e); if (qdict_haskey(cpu, "qom-path")) { + qobject_unref(e); continue; } @@ -107,6 +108,7 @@ static void test_plug_with_device_add(gconstpointer data) qtest_qmp_device_add_qdict(qts, td->device_model, props); hotplugged++; + qobject_unref(e); } /* make sure that there were hotplugged CPUs */ diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c index 1d3147f821..5dc807ba23 100644 --- a/tests/fw_cfg-test.c +++ b/tests/fw_cfg-test.c @@ -194,6 +194,26 @@ static void test_fw_cfg_reboot_timeout(void) qtest_quit(s); } +static void test_fw_cfg_no_reboot_timeout(void) +{ + QFWCFG *fw_cfg; + QTestState *s; + uint32_t reboot_timeout = 0; + size_t filesize; + + /* Special value -1 means "don't reboot" */ + s = qtest_init("-boot reboot-timeout=-1"); + fw_cfg = pc_fw_cfg_init(s); + + filesize = qfw_cfg_get_file(fw_cfg, "etc/boot-fail-wait", + &reboot_timeout, sizeof(reboot_timeout)); + g_assert_cmpint(filesize, ==, sizeof(reboot_timeout)); + reboot_timeout = le32_to_cpu(reboot_timeout); + g_assert_cmpint(reboot_timeout, ==, UINT32_MAX); + pc_fw_cfg_uninit(fw_cfg); + qtest_quit(s); +} + static void test_fw_cfg_splash_time(void) { QFWCFG *fw_cfg; @@ -233,6 +253,7 @@ int main(int argc, char **argv) qtest_add_func("fw_cfg/numa", test_fw_cfg_numa); qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu); qtest_add_func("fw_cfg/reboot_timeout", test_fw_cfg_reboot_timeout); + qtest_add_func("fw_cfg/no_reboot_timeout", test_fw_cfg_no_reboot_timeout); qtest_add_func("fw_cfg/splash_time", test_fw_cfg_splash_time); return g_test_run(); diff --git a/tests/image-fuzzer/qcow2/__init__.py b/tests/image-fuzzer/qcow2/__init__.py index 09ef59821b..ed3af5da86 100644 --- a/tests/image-fuzzer/qcow2/__init__.py +++ b/tests/image-fuzzer/qcow2/__init__.py @@ -1,2 +1 @@ -from __future__ import absolute_import from .layout import create_image diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py index abc4f0635d..c58bf11005 100644 --- a/tests/image-fuzzer/qcow2/fuzz.py +++ b/tests/image-fuzzer/qcow2/fuzz.py @@ -27,20 +27,20 @@ UINT64 = 0xffffffffffffffff UINT32_M = 31 UINT64_M = 63 # Fuzz vectors -UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1, +UINT8_V = [0, 0x10, UINT8//4, UINT8//2 - 1, UINT8//2, UINT8//2 + 1, UINT8 - 1, UINT8] -UINT16_V = [0, 0x100, 0x1000, UINT16/4, UINT16/2 - 1, UINT16/2, UINT16/2 + 1, +UINT16_V = [0, 0x100, 0x1000, UINT16//4, UINT16//2 - 1, UINT16//2, UINT16//2 + 1, UINT16 - 1, UINT16] -UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1, - UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32] -UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4, - UINT64/2 - 1, UINT64/2, UINT64/2 + 1, UINT64 - 1, +UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32//4, UINT32//2 - 1, + UINT32//2, UINT32//2 + 1, UINT32 - 1, UINT32] +UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64//4, + UINT64//2 - 1, UINT64//2, UINT64//2 + 1, UINT64 - 1, UINT64] -STRING_V = ['%s%p%x%d', '.1024d', '%.2049d', '%p%p%p%p', '%x%x%x%x', - '%d%d%d%d', '%s%s%s%s', '%99999999999s', '%08x', '%%20d', '%%20n', - '%%20x', '%%20s', '%s%s%s%s%s%s%s%s%s%s', '%p%p%p%p%p%p%p%p%p%p', - '%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', - '%s x 129', '%x x 257'] +BYTES_V = [b'%s%p%x%d', b'.1024d', b'%.2049d', b'%p%p%p%p', b'%x%x%x%x', + b'%d%d%d%d', b'%s%s%s%s', b'%99999999999s', b'%08x', b'%%20d', b'%%20n', + b'%%20x', b'%%20s', b'%s%s%s%s%s%s%s%s%s%s', b'%p%p%p%p%p%p%p%p%p%p', + b'%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%', + b'%s x 129', b'%x x 257'] def random_from_intervals(intervals): @@ -76,12 +76,12 @@ def random_bits(bit_ranges): return val -def truncate_string(strings, length): - """Return strings truncated to specified length.""" - if type(strings) == list: - return [s[:length] for s in strings] +def truncate_bytes(sequences, length): + """Return sequences truncated to specified length.""" + if type(sequences) == list: + return [s[:length] for s in sequences] else: - return strings[:length] + return sequences[:length] def validator(current, pick, choices): @@ -110,12 +110,12 @@ def bit_validator(current, bit_ranges): return validator(current, random_bits, bit_ranges) -def string_validator(current, strings): - """Return a random string value from the list not equal to the current. +def bytes_validator(current, sequences): + """Return a random bytes value from the list not equal to the current. This function is useful for selection from valid values except current one. """ - return validator(current, random.choice, strings) + return validator(current, random.choice, sequences) def selector(current, constraints, validate=int_validator): @@ -283,9 +283,9 @@ def header_length(current): def bf_name(current): """Fuzz the backing file name.""" constraints = [ - truncate_string(STRING_V, len(current)) + truncate_bytes(BYTES_V, len(current)) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def ext_magic(current): @@ -303,10 +303,10 @@ def ext_length(current): def bf_format(current): """Fuzz backing file format in the corresponding header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, (len(current) + 7) & ~7) # Fuzz padding + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, (len(current) + 7) & ~7) # Fuzz padding ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def feature_type(current): @@ -324,10 +324,10 @@ def feature_bit_number(current): def feature_name(current): """Fuzz feature name field of a feature name table header extension.""" constraints = [ - truncate_string(STRING_V, len(current)), - truncate_string(STRING_V, 46) # Fuzz padding (field length = 46) + truncate_bytes(BYTES_V, len(current)), + truncate_bytes(BYTES_V, 46) # Fuzz padding (field length = 46) ] - return selector(current, constraints, string_validator) + return selector(current, constraints, bytes_validator) def l1_entry(current): diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py index 675877da96..57ebe86e9a 100644 --- a/tests/image-fuzzer/qcow2/layout.py +++ b/tests/image-fuzzer/qcow2/layout.py @@ -16,7 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import absolute_import import random import struct from . import fuzz @@ -53,8 +52,8 @@ class Field(object): return iter([self.fmt, self.offset, self.value, self.name]) def __repr__(self): - return "Field(fmt='%s', offset=%d, value=%s, name=%s)" % \ - (self.fmt, self.offset, str(self.value), self.name) + return "Field(fmt=%r, offset=%r, value=%r, name=%r)" % \ + (self.fmt, self.offset, self.value, self.name) class FieldsList(object): @@ -122,7 +121,7 @@ class Image(object): def create_header(self, cluster_bits, backing_file_name=None): """Generate a random valid header.""" meta_header = [ - ['>4s', 0, "QFI\xfb", 'magic'], + ['>4s', 0, b"QFI\xfb", 'magic'], ['>I', 4, random.randint(2, 3), 'version'], ['>Q', 8, 0, 'backing_file_offset'], ['>I', 16, 0, 'backing_file_size'], @@ -231,7 +230,7 @@ class Image(object): feature_tables = [] feature_ids = [] inner_offset = self.ext_offset + ext_header_len - feat_name = 'some cool feature' + feat_name = b'some cool feature' while len(feature_tables) < num_fnt_entries * 3: feat_type, feat_bit = gen_feat_ids() # Remove duplicates @@ -253,7 +252,7 @@ class Image(object): ['>I', self.ext_offset, 0x6803f857, 'ext_magic'], # One feature table contains 3 fields and takes 48 bytes ['>I', self.ext_offset + UINT32_S, - len(feature_tables) / 3 * 48, 'ext_length'] + len(feature_tables) // 3 * 48, 'ext_length'] ] + feature_tables) self.ext_offset = inner_offset @@ -271,7 +270,7 @@ class Image(object): def create_l2_entry(host, guest, l2_cluster): """Generate one L2 entry.""" offset = l2_cluster * self.cluster_size - l2_size = self.cluster_size / UINT64_S + l2_size = self.cluster_size // UINT64_S entry_offset = offset + UINT64_S * (guest % l2_size) cluster_descriptor = host * self.cluster_size if not self.header['version'][0].value == 2: @@ -283,8 +282,8 @@ class Image(object): def create_l1_entry(l2_cluster, l1_offset, guest): """Generate one L1 entry.""" - l2_size = self.cluster_size / UINT64_S - entry_offset = l1_offset + UINT64_S * (guest / l2_size) + l2_size = self.cluster_size // UINT64_S + entry_offset = l1_offset + UINT64_S * (guest // l2_size) # While snapshots are not supported bit #63 = 1 entry_val = (1 << 63) + l2_cluster * self.cluster_size return ['>Q', entry_offset, entry_val, 'l1_entry'] @@ -298,11 +297,11 @@ class Image(object): l2 = [] else: meta_data = self._get_metadata() - guest_clusters = random.sample(range(self.image_size / + guest_clusters = random.sample(range(self.image_size // self.cluster_size), len(self.data_clusters)) # Number of entries in a L1/L2 table - l_size = self.cluster_size / UINT64_S + l_size = self.cluster_size // UINT64_S # Number of clusters necessary for L1 table l1_size = int(ceil((max(guest_clusters) + 1) / float(l_size**2))) l1_start = self._get_adjacent_clusters(self.data_clusters | @@ -318,7 +317,7 @@ class Image(object): # L2 entries l2 = [] for host, guest in zip(self.data_clusters, guest_clusters): - l2_id = guest / l_size + l2_id = guest // l_size if l2_id not in l2_ids: l2_ids.append(l2_id) l2_clusters.append(self._get_adjacent_clusters( @@ -339,14 +338,14 @@ class Image(object): def allocate_rfc_blocks(data, size): """Return indices of clusters allocated for refcount blocks.""" cluster_ids = set() - diff = block_ids = set([x / size for x in data]) + diff = block_ids = set([x // size for x in data]) while len(diff) != 0: # Allocate all yet not allocated clusters new = self._get_available_clusters(data | cluster_ids, len(diff)) # Indices of new refcount blocks necessary to cover clusters # in 'new' - diff = set([x / size for x in new]) - block_ids + diff = set([x // size for x in new]) - block_ids cluster_ids |= new block_ids |= diff return cluster_ids, block_ids @@ -359,7 +358,7 @@ class Image(object): blocks = set(init_blocks) clusters = set() # Number of entries in one cluster of the refcount table - size = self.cluster_size / UINT64_S + size = self.cluster_size // UINT64_S # Number of clusters necessary for the refcount table based on # the current number of refcount blocks table_size = int(ceil((max(blocks) + 1) / float(size))) @@ -373,7 +372,7 @@ class Image(object): table_size + 1)) # New refcount blocks necessary for clusters occupied by the # refcount table - diff = set([c / block_size for c in table_clusters]) - blocks + diff = set([c // block_size for c in table_clusters]) - blocks blocks |= diff while len(diff) != 0: # Allocate clusters for new refcount blocks @@ -382,12 +381,12 @@ class Image(object): len(diff)) # Indices of new refcount blocks necessary to cover # clusters in 'new' - diff = set([x / block_size for x in new]) - blocks + diff = set([x // block_size for x in new]) - blocks clusters |= new blocks |= diff # Check if the refcount table needs one more cluster if int(ceil((max(blocks) + 1) / float(size))) > table_size: - new_block_id = (table_start + table_size) / block_size + new_block_id = (table_start + table_size) // block_size # Check if the additional table cluster needs # one more refcount block if new_block_id not in blocks: @@ -399,13 +398,13 @@ class Image(object): def create_table_entry(table_offset, block_cluster, block_size, cluster): """Generate a refcount table entry.""" - offset = table_offset + UINT64_S * (cluster / block_size) + offset = table_offset + UINT64_S * (cluster // block_size) return ['>Q', offset, block_cluster * self.cluster_size, 'refcount_table_entry'] def create_block_entry(block_cluster, block_size, cluster): """Generate a list of entries for the current block.""" - entry_size = self.cluster_size / block_size + entry_size = self.cluster_size // block_size offset = block_cluster * self.cluster_size entry_offset = offset + entry_size * (cluster % block_size) # While snapshots are not supported all refcounts are set to 1 @@ -415,7 +414,7 @@ class Image(object): # Number of refcount entries per refcount block # Convert self.cluster_size from bytes to bits to have the same # base for the numerator and denominator - block_size = self.cluster_size * 8 / refcount_bits + block_size = self.cluster_size * 8 // refcount_bits meta_data = self._get_metadata() if len(self.data_clusters) == 0: # All metadata for an empty guest image needs 4 clusters: @@ -452,8 +451,8 @@ class Image(object): rfc_blocks = [] for cluster in sorted(self.data_clusters | meta_data): - if cluster / block_size != block_id: - block_id = cluster / block_size + if cluster // block_size != block_id: + block_id = cluster // block_size block_cluster = block_clusters[block_ids.index(block_id)] rfc_table.append(create_table_entry(table_offset, block_cluster, @@ -503,7 +502,7 @@ class Image(object): def write(self, filename): """Write an entire image to the file.""" - image_file = open(filename, 'w') + image_file = open(filename, 'wb') for field in self: image_file.seek(field.offset) image_file.write(struct.pack(field.fmt, field.value)) @@ -518,7 +517,7 @@ class Image(object): rounded = (size + self.cluster_size - 1) & ~(self.cluster_size - 1) if rounded > size: image_file.seek(rounded - 1) - image_file.write("\0") + image_file.write(b'\x00') image_file.close() @staticmethod @@ -587,7 +586,7 @@ class Image(object): def _alloc_data(img_size, cluster_size): """Return a set of random indices of clusters allocated for guest data. """ - num_of_cls = img_size/cluster_size + num_of_cls = img_size // cluster_size return set(random.sample(range(1, num_of_cls + 1), random.randint(0, num_of_cls))) @@ -595,15 +594,15 @@ class Image(object): """Return indices of clusters allocated for image metadata.""" ids = set() for x in self: - ids.add(x.offset/self.cluster_size) + ids.add(x.offset // self.cluster_size) return ids def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None, fields_to_fuzz=None): """Create a fuzzed image and write it to the specified file.""" - image = Image(backing_file_name) - image.set_backing_file_format(backing_file_fmt) + image = Image(backing_file_name.encode()) + image.set_backing_file_format(backing_file_fmt.encode()) image.create_feature_name_table() image.set_end_of_extension_area() image.create_l_structures() diff --git a/tests/image-fuzzer/runner.py b/tests/image-fuzzer/runner.py index 95d84f38f3..2fc010fd9d 100755 --- a/tests/image-fuzzer/runner.py +++ b/tests/image-fuzzer/runner.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Tool for running fuzz tests # @@ -18,7 +18,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from __future__ import print_function import sys import os import signal @@ -28,7 +27,7 @@ import shutil from itertools import count import time import getopt -import StringIO +import io import resource try: @@ -80,7 +79,8 @@ def run_app(fd, q_args): devnull = open('/dev/null', 'r+') process = subprocess.Popen(q_args, stdin=devnull, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + errors='replace') try: out, err = process.communicate() signal.alarm(0) @@ -159,7 +159,7 @@ class TestEnv(object): os.makedirs(self.current_dir) except OSError as e: print("Error: The working directory '%s' cannot be used. Reason: %s"\ - % (self.work_dir, e[1]), file=sys.stderr) + % (self.work_dir, e.strerror), file=sys.stderr) raise TestException self.log = open(os.path.join(self.current_dir, "test.log"), "w") self.parent_log = open(run_log, "a") @@ -183,7 +183,7 @@ class TestEnv(object): MAX_BACKING_FILE_SIZE) * (1 << 20) cmd = self.qemu_img + ['create', '-f', backing_file_fmt, backing_file_name, str(backing_file_size)] - temp_log = StringIO.StringIO() + temp_log = io.StringIO() retcode = run_app(temp_log, cmd) if retcode == 0: temp_log.close() @@ -240,13 +240,13 @@ class TestEnv(object): "Backing file: %s\n" \ % (self.seed, " ".join(current_cmd), self.current_dir, backing_file_name) - temp_log = StringIO.StringIO() + temp_log = io.StringIO() try: retcode = run_app(temp_log, current_cmd) except OSError as e: multilog("%sError: Start of '%s' failed. Reason: %s\n\n" % (test_summary, os.path.basename(current_cmd[0]), - e[1]), + e.strerror), sys.stderr, self.log, self.parent_log) raise TestException diff --git a/tests/libqtest.c b/tests/libqtest.c index 3706bccd8d..91e9cb220c 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -1274,6 +1274,7 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, qdict_put_str(args, "id", id); qtest_qmp_device_add_qdict(qts, driver, args); + qobject_unref(args); } static void device_deleted_cb(void *opaque, const char *name, QDict *data) diff --git a/tests/migration-test.c b/tests/migration-test.c index 59f291c654..ac780dffda 100644 --- a/tests/migration-test.c +++ b/tests/migration-test.c @@ -899,8 +899,13 @@ static void wait_for_migration_fail(QTestState *from, bool allow_active) do { status = migrate_query_status(from); - g_assert(!strcmp(status, "setup") || !strcmp(status, "failed") || - (allow_active && !strcmp(status, "active"))); + bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || + (allow_active && !strcmp(status, "active")); + if (!result) { + fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", + __func__, status, allow_active); + } + g_assert(result); failed = !strcmp(status, "failed"); g_free(status); } while (!failed); diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c index 45e1de5bd6..f30bea08dc 100644 --- a/tests/plugin/bb.c +++ b/tests/plugin/bb.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t bb_count; static uint64_t insn_count; static bool do_inline; diff --git a/tests/plugin/empty.c b/tests/plugin/empty.c index 3f60f69027..8fa6bacd93 100644 --- a/tests/plugin/empty.c +++ b/tests/plugin/empty.c @@ -13,6 +13,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + /* * Empty TB translation callback. * This allows us to measure the overhead of injecting and then diff --git a/tests/plugin/hotblocks.c b/tests/plugin/hotblocks.c index 1bd183849a..3942a2ca54 100644 --- a/tests/plugin/hotblocks.c +++ b/tests/plugin/hotblocks.c @@ -15,6 +15,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static bool do_inline; /* Plugins need to take care of their own locking */ diff --git a/tests/plugin/hotpages.c b/tests/plugin/hotpages.c index 77df07a3cc..ecd6c18732 100644 --- a/tests/plugin/hotpages.c +++ b/tests/plugin/hotpages.c @@ -18,6 +18,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static uint64_t page_size = 4096; diff --git a/tests/plugin/howvec.c b/tests/plugin/howvec.c index 58fa675e34..4ca555e123 100644 --- a/tests/plugin/howvec.c +++ b/tests/plugin/howvec.c @@ -20,6 +20,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) typedef enum { diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c index e5fd07fb64..0a8f5a0000 100644 --- a/tests/plugin/insn.c +++ b/tests/plugin/insn.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t insn_count; static bool do_inline; diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c index d967388989..878abf09d1 100644 --- a/tests/plugin/mem.c +++ b/tests/plugin/mem.c @@ -14,6 +14,8 @@ #include <qemu-plugin.h> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + static uint64_t mem_count; static uint64_t io_count; static bool do_inline; diff --git a/tests/qemu-iotests/272 b/tests/qemu-iotests/272 new file mode 100755 index 0000000000..c2f782d47b --- /dev/null +++ b/tests/qemu-iotests/272 @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# +# Test compressed write to a qcow2 image at an offset above 4 GB +# +# Copyright (C) 2019 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +seq=$(basename "$0") +echo "QA output created by $seq" + +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 is a qcow2 regression test +_supported_fmt qcow2 +_supported_proto file + +# External data files do not support compression; +# We need an exact cluster size (2M) and refcount width (2) so we can +# get this test quickly over with; and this in turn require +# compat=1.1 +_unsupported_imgopts data_file cluster_size refcount_bits 'compat=0.10' + +# The idea is: Create an empty file, mark the first 4 GB as used, then +# do a compressed write that thus must be put beyond 4 GB. +# (This used to fail because the compressed sector mask was just a +# 32 bit mask, so qemu-img check will count a cluster before 4 GB as +# referenced twice.) + +# We would like to use refcount_bits=1 here, but then qemu-img check +# will throw an error when trying to count a cluster as referenced +# twice. +_make_test_img -o cluster_size=2M,refcount_bits=2 64M + +reft_offs=$(peek_file_be "$TEST_IMG" 48 8) +refb_offs=$(peek_file_be "$TEST_IMG" $reft_offs 8) + +# We want to cover 4 GB, those are 2048 clusters, equivalent to +# 4096 bit = 512 B. +truncate -s 4G "$TEST_IMG" +for ((in_refb_offs = 0; in_refb_offs < 512; in_refb_offs += 8)); do + poke_file "$TEST_IMG" $((refb_offs + in_refb_offs)) \ + '\x55\x55\x55\x55\x55\x55\x55\x55' +done + +$QEMU_IO -c 'write -c -P 42 0 2M' "$TEST_IMG" | _filter_qemu_io + +echo +echo '--- Check ---' + +# This should only print the leaked clusters in the first 4 GB +_check_test_img | grep -v '^Leaked cluster ' + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/272.out b/tests/qemu-iotests/272.out new file mode 100644 index 0000000000..35698b0e73 --- /dev/null +++ b/tests/qemu-iotests/272.out @@ -0,0 +1,10 @@ +QA output created by 272 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 2097152/2097152 bytes at offset 0 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +--- Check --- + +2044 leaked clusters were found on the image. +This means waste of disk space, but no harm to data. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 095ed1b880..065040398d 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -283,3 +283,4 @@ 267 rw auto quick snapshot 268 rw auto quick 270 rw backing quick +272 rw diff --git a/tests/tcg/multiarch/linux-test.c b/tests/tcg/multiarch/linux-test.c index fa4243fc04..673d7c8a1c 100644 --- a/tests/tcg/multiarch/linux-test.c +++ b/tests/tcg/multiarch/linux-test.c @@ -503,8 +503,9 @@ static void test_shm(void) shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); ptr = shmat(shmid, NULL, 0); - if (!ptr) + if (ptr == (void *)-1) { error("shmat"); + } memset(ptr, 0, SHM_SIZE); diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 2929de23aa..91a9226026 100755 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -95,19 +95,25 @@ class BaseVM(object): logging.info("KVM not available, not using -enable-kvm") self._data_args = [] - def _download_with_cache(self, url, sha256sum=None): + def _download_with_cache(self, url, sha256sum=None, sha512sum=None): def check_sha256sum(fname): if not sha256sum: return True checksum = subprocess.check_output(["sha256sum", fname]).split()[0] return sha256sum == checksum.decode("utf-8") + def check_sha512sum(fname): + if not sha512sum: + return True + checksum = subprocess.check_output(["sha512sum", fname]).split()[0] + return sha512sum == checksum.decode("utf-8") + cache_dir = os.path.expanduser("~/.cache/qemu-vm/download") if not os.path.exists(cache_dir): os.makedirs(cache_dir) fname = os.path.join(cache_dir, hashlib.sha1(url.encode("utf-8")).hexdigest()) - if os.path.exists(fname) and check_sha256sum(fname): + if os.path.exists(fname) and check_sha256sum(fname) and check_sha512sum(fname): return fname logging.debug("Downloading %s to %s...", url, fname) subprocess.check_call(["wget", "-c", url, "-O", fname + ".download"], @@ -242,6 +248,25 @@ class BaseVM(object): return False return True + def console_consume(self): + vm = self._guest + output = "" + vm.console_socket.setblocking(0) + while True: + try: + chars = vm.console_socket.recv(1) + except: + break + output += chars.decode("latin1") + if "\r" in output or "\n" in output: + lines = re.split("[\r\n]", output) + output = lines.pop() + if self.debug: + self.console_log("\n".join(lines)) + if self.debug: + self.console_log(output) + vm.console_socket.setblocking(1) + def console_send(self, command): vm = self._guest if self.debug: diff --git a/tests/vm/netbsd b/tests/vm/netbsd index 18aa56ae82..611e6cc5b5 100755 --- a/tests/vm/netbsd +++ b/tests/vm/netbsd @@ -2,10 +2,11 @@ # # NetBSD VM image # -# Copyright 2017 Red Hat Inc. +# Copyright 2017-2019 Red Hat Inc. # # Authors: # Fam Zheng <famz@redhat.com> +# Gerd Hoffmann <kraxel@redhat.com> # # This code is licensed under the GPL version 2 or later. See # the COPYING file in the top-level directory. @@ -13,20 +14,54 @@ import os import sys +import time import subprocess import basevm class NetBSDVM(basevm.BaseVM): name = "netbsd" arch = "x86_64" + + link = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-8.1/images/NetBSD-8.1-amd64.iso" + csum = "718f275b7e0879599bdac95630c5e3f2184700032fdb6cdebf3bdd63687898c48ff3f08f57b89f4437a86cdd8ea07c01a39d432dbb37e1e4b008f4985f98da3f" + size = "20G" + pkgs = [ + # tools + "git-base", + "pkgconf", + "xz", + "python37", + + # gnu tools + "bash", + "gmake", + "gsed", + "flex", "bison", + + # libs: crypto + "gnutls", + + # libs: images + "jpeg", + "png", + + # libs: ui + "SDL2", + "gtk3+", + "libxkbcommon", + ] + BUILD_SCRIPT = """ set -e; - rm -rf /var/tmp/qemu-test.* - cd $(mktemp -d /var/tmp/qemu-test.XXXXXX); + rm -rf /home/qemu/qemu-test.* + cd $(mktemp -d /home/qemu/qemu-test.XXXXXX); + mkdir src build; cd src; tar -xf /dev/rld1a; - ./configure --python=python2.7 {configure_opts}; + cd ../build + ../src/configure --python=python3.7 --disable-opengl {configure_opts}; gmake --output-sync -j{jobs} {target} {verbose}; """ + poweroff = "/sbin/poweroff" # Workaround for NetBSD + IPv6 + slirp issues. # NetBSD seems to ignore the ICMPv6 Destination Unreachable @@ -36,14 +71,147 @@ class NetBSDVM(basevm.BaseVM): ipv6 = False def build_image(self, img): - cimg = self._download_with_cache("http://download.patchew.org/netbsd-7.1-amd64.img.xz", - sha256sum='b633d565b0eac3d02015cd0c81440bd8a7a8df8512615ac1ee05d318be015732') - img_tmp_xz = img + ".tmp.xz" + cimg = self._download_with_cache(self.link, sha512sum=self.csum) img_tmp = img + ".tmp" - sys.stderr.write("Extracting the image...\n") - subprocess.check_call(["ln", "-f", cimg, img_tmp_xz]) - subprocess.check_call(["xz", "--keep", "-dvf", img_tmp_xz]) + iso = img + ".install.iso" + + self.print_step("Preparing iso and disk image") + subprocess.check_call(["ln", "-f", cimg, iso]) + subprocess.check_call(["qemu-img", "create", "-f", "qcow2", + img_tmp, self.size]) + + self.print_step("Booting installer") + self.boot(img_tmp, extra_args = [ + "-bios", "pc-bios/bios-256k.bin", + "-machine", "graphics=off", + "-cdrom", iso + ]) + self.console_init() + self.console_wait("Primary Bootstrap") + + # serial console boot menu output doesn't work for some + # reason, so we have to fly blind ... + for char in list("5consdev com0\n"): + time.sleep(0.2) + self.console_send(char) + self.console_consume() + self.console_wait_send("> ", "boot\n") + + self.console_wait_send("Terminal type", "xterm\n") + self.console_wait_send("a: Installation messages", "a\n") + self.console_wait_send("b: US-English", "b\n") + self.console_wait_send("a: Install NetBSD", "a\n") + self.console_wait("Shall we continue?") + self.console_wait_send("b: Yes", "b\n") + + self.console_wait_send("a: ld0", "a\n") + self.console_wait_send("a: This is the correct", "a\n") + self.console_wait_send("b: Use the entire disk", "b\n") + self.console_wait("NetBSD bootcode") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("b: Use existing part", "b\n") + self.console_wait_send("x: Partition sizes ok", "x\n") + self.console_wait_send("for your NetBSD disk", "\n") + self.console_wait("Shall we continue?") + self.console_wait_send("b: Yes", "b\n") + + self.console_wait_send("b: Use serial port com0", "b\n") + self.console_wait_send("f: Set serial baud rate", "f\n") + self.console_wait_send("a: 9600", "a\n") + self.console_wait_send("x: Exit", "x\n") + + self.console_wait_send("a: Full installation", "a\n") + self.console_wait_send("a: CD-ROM", "a\n") + + self.print_step("Installation started now, this will take a while") + self.console_wait_send("Hit enter to continue", "\n") + + self.console_wait_send("d: Change root password", "d\n") + self.console_wait_send("a: Yes", "a\n") + self.console_wait("New password:") + self.console_send("%s\n" % self.ROOT_PASS) + self.console_wait("New password:") + self.console_send("%s\n" % self.ROOT_PASS) + self.console_wait("Retype new password:") + self.console_send("%s\n" % self.ROOT_PASS) + + self.console_wait_send("o: Add a user", "o\n") + self.console_wait("username") + self.console_send("%s\n" % self.GUEST_USER) + self.console_wait("to group wheel") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("a: /bin/sh", "a\n") + self.console_wait("New password:") + self.console_send("%s\n" % self.GUEST_PASS) + self.console_wait("New password:") + self.console_send("%s\n" % self.GUEST_PASS) + self.console_wait("Retype new password:") + self.console_send("%s\n" % self.GUEST_PASS) + + self.console_wait_send("a: Configure network", "a\n") + self.console_wait_send("a: vioif0", "a\n") + self.console_wait_send("Network media type", "\n") + self.console_wait("autoconfiguration") + self.console_wait_send("a: Yes", "a\n") + self.console_wait_send("DNS domain", "localnet\n") + self.console_wait("Are they OK?") + self.console_wait_send("a: Yes", "a\n") + self.console_wait("installed in /etc") + self.console_wait_send("a: Yes", "a\n") + + self.console_wait_send("e: Enable install", "e\n") + proxy = os.environ.get("http_proxy") + if not proxy is None: + self.console_wait_send("f: Proxy", "f\n") + self.console_wait("Proxy") + self.console_send("%s\n" % proxy) + self.console_wait_send("x: Install pkgin", "x\n") + self.console_init(1200) + self.console_wait_send("Hit enter to continue", "\n") + self.console_init() + + self.console_wait_send("g: Enable sshd", "g\n") + self.console_wait_send("x: Finished conf", "x\n") + self.console_wait_send("Hit enter to continue", "\n") + + self.print_step("Installation finished, rebooting") + self.console_wait_send("d: Reboot the computer", "d\n") + + # setup qemu user + prompt = "localhost$" + self.console_ssh_init(prompt, self.GUEST_USER, self.GUEST_PASS) + self.console_wait_send(prompt, "exit\n") + + # setup root user + prompt = "localhost#" + self.console_ssh_init(prompt, "root", self.ROOT_PASS) + self.console_sshd_config(prompt) + + # setup virtio-blk #1 (tarfile) + self.console_wait(prompt) + self.console_send("echo 'chmod 666 /dev/rld1a' >> /etc/rc.local\n") + + # turn off mprotect (conflicts with tcg) + self.console_wait(prompt) + self.console_send("echo security.pax.mprotect.enabled=0 >> /etc/sysctl.conf\n") + + self.print_step("Configuration finished, rebooting") + self.console_wait_send(prompt, "reboot\n") + self.console_wait("login:") + self.wait_ssh() + + self.print_step("Installing packages") + self.ssh_root_check("pkgin update\n") + self.ssh_root_check("pkgin -y install %s\n" % " ".join(self.pkgs)) + + # shutdown + self.ssh_root(self.poweroff) + self.console_wait("entering state S5") + self.wait() + os.rename(img_tmp, img) + os.remove(iso) + self.print_step("All done") if __name__ == "__main__": sys.exit(basevm.main(NetBSDVM)) |