@@ -68,6 +68,7 @@ static QTestMigrationState dst_state;
#define QEMU_VM_FILE_MAGIC 0x5145564d
#define FILE_TEST_FILENAME "migfile"
#define FILE_TEST_OFFSET 0x1000
+#define FILE_TEST_MARKER 'X'
#define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
#define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
@@ -1693,10 +1694,43 @@ finish:
test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
}
+static void file_dirty_offset_region(void)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+ size_t size = FILE_TEST_OFFSET;
+ g_autofree char *data = g_new0(char, size);
+
+ memset(data, FILE_TEST_MARKER, size);
+ g_assert(g_file_set_contents(path, data, size, NULL));
+}
+
+static void file_check_offset_region(void)
+{
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+ size_t size = FILE_TEST_OFFSET;
+ g_autofree char *expected = g_new0(char, size);
+ g_autofree char *actual = NULL;
+ uint64_t *stream_start;
+
+ /*
+ * Ensure the skipped offset region's data has not been touched
+ * and the migration stream starts at the right place.
+ */
+
+ memset(expected, FILE_TEST_MARKER, size);
+
+ g_assert(g_file_get_contents(path, &actual, NULL, NULL));
+ g_assert(!memcmp(actual, expected, size));
+
+ stream_start = (uint64_t *)(actual + size);
+ g_assert_cmpint(cpu_to_be64(*stream_start) >> 32, ==, QEMU_VM_FILE_MAGIC);
+}
+
static void test_file_common(MigrateCommon *args, bool stop_src)
{
QTestState *from, *to;
void *data_hook = NULL;
+ bool check_offset = false;
if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
return;
@@ -1709,6 +1743,16 @@ static void test_file_common(MigrateCommon *args, bool stop_src)
*/
g_assert_false(args->live);
+ if (g_strrstr(args->connect_uri, "offset=")) {
+ check_offset = true;
+ /*
+ * This comes before the start_hook because it's equivalent to
+ * a management application creating the file and writing to
+ * it so hooks should expect the file to be already present.
+ */
+ file_dirty_offset_region();
+ }
+
if (args->start_hook) {
data_hook = args->start_hook(from, to);
}
@@ -1743,6 +1787,10 @@ static void test_file_common(MigrateCommon *args, bool stop_src)
wait_for_serial("dest_serial");
+ if (check_offset) {
+ file_check_offset_region();
+ }
+
finish:
if (args->finish_hook) {
args->finish_hook(from, to, data_hook);
@@ -1942,36 +1990,6 @@ static void test_precopy_file(void)
test_file_common(&args, true);
}
-static void file_offset_finish_hook(QTestState *from, QTestState *to,
- void *opaque)
-{
-#if defined(__linux__)
- g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
- size_t size = FILE_TEST_OFFSET + sizeof(QEMU_VM_FILE_MAGIC);
- uintptr_t *addr, *p;
- int fd;
-
- fd = open(path, O_RDONLY);
- g_assert(fd != -1);
- addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- g_assert(addr != MAP_FAILED);
-
- /*
- * Ensure the skipped offset contains zeros and the migration
- * stream starts at the right place.
- */
- p = addr;
- while (p < addr + FILE_TEST_OFFSET / sizeof(uintptr_t)) {
- g_assert(*p == 0);
- p++;
- }
- g_assert_cmpint(cpu_to_be64(*p) >> 32, ==, QEMU_VM_FILE_MAGIC);
-
- munmap(addr, size);
- close(fd);
-#endif
-}
-
static void test_precopy_file_offset(void)
{
g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
@@ -1980,7 +1998,6 @@ static void test_precopy_file_offset(void)
MigrateCommon args = {
.connect_uri = uri,
.listen_uri = "defer",
- .finish_hook = file_offset_finish_hook,
};
test_file_common(&args, false);