@samitouri / QOSamiQemu / commits / 5be90dfbc0

tests/qtest/ide-test: cover a rejected CHS translation in the stream

ide_drive_post_load() refuses a logical CHS translation that no command could have selected, as the fields are a divisor in ide_set_sector() and a factor in ide_get_sector(). Nothing exercised that, a fixed QEMU having no way to produce such a stream. Migrate a guest that selected a translation to a file, replace the number of sectors per logical track in the subsection with a zero, and let a destination read the result back. The load has to fail rather than take the value, so the destination is asked not to exit on a failed incoming migration and its migration status is what the test looks at. Cc: John Snow <jsnow@redhat.com> Cc: Peter Maydell <peter.maydell@linaro.org> Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Denis V. Lunev <den@openvz.org>

Denis V. Lunev committed Aug 14, 2026 at 18:17 UTC 5be90dfbc000a279b7cec668f9dbb131ce2b0c40
1 file changed +81
tests/qtest/ide-test.c
+81
@@ -1483,6 +1483,86 @@ static void test_migrate_chs_snapshot(void)
1483 unlink(img);
1484 }
1485
1486 +/* A migration stream holds NUL bytes, so this cannot be a string search */
1487 +static char *ide_stream_find(char *stream, gsize len, const char *name)
1488 +{
1489 + gsize name_len = strlen(name);
1490 + gsize i;
1491 +
1492 + if (len < name_len) {
1493 + return NULL;
1494 + }
1495 + for (i = 0; i <= len - name_len; i++) {
1496 + if (memcmp(stream + i, name, name_len) == 0) {
1497 + return stream + i;
1498 + }
1499 + }
1500 +
1501 + return NULL;
1502 +}
1503 +
1504 +/* A translation no command could have selected has to be refused on load */
1505 +static void test_migrate_chs_rejected(void)
1506 +{
1507 + const char *name = "ide_drive/chs_translation";
1508 + QTestState *src, *dst;
1509 + QPCIDevice *dev;
1510 + QPCIBar bmdma_bar, ide_bar;
1511 + g_autofree char *path = NULL;
1512 + g_autofree char *uri = NULL;
1513 + g_autofree char *dst_args = NULL;
1514 + g_autofree char *stream = NULL;
1515 + char *subsection;
1516 + gsize len;
1517 + int fd;
1518 +
1519 + fd = g_file_open_tmp("qtest-ide-stream.XXXXXX", &path, NULL);
1520 + g_assert(fd >= 0);
1521 + close(fd);
1522 + uri = g_strdup_printf("file:%s", path);
1523 +
1524 + src = ide_test_start(
1525 + "-blockdev driver=file,node-name=hda,filename=%s "
1526 + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ",
1527 + tmp_path[0]);
1528 + dev = get_pci_device(src, &bmdma_bar, &ide_bar);
1529 +
1530 + ide_set_translation(dev, ide_bar, 8, 32);
1531 + qtest_qmp_assert_success(src, "{ 'execute': 'migrate',"
1532 + " 'arguments': { 'uri': %s } }", uri);
1533 + qtest_qmp_eventwait(src, "STOP");
1534 + ide_migration_wait(src, "completed");
1535 + free_pci_device(dev);
1536 + ide_test_quit(src);
1537 +
1538 + /*
1539 + * Behind the name come version, heads and sectors, each big endian 32 bit.
1540 + * The name recurs in the description at the end of the stream, so the
1541 + * first match is the one carrying data.
1542 + */
1543 + g_assert(g_file_get_contents(path, &stream, &len, NULL));
1544 + subsection = ide_stream_find(stream, len, name);
1545 + g_assert(subsection);
1546 + g_assert_cmpint(subsection - stream + strlen(name) + 12, <=, len);
1547 + memset(subsection + strlen(name) + 8, 0, 4);
1548 + g_assert(g_file_set_contents(path, stream, len, NULL));
1549 +
1550 + dst_args = g_strdup_printf(
1551 + "-machine pc "
1552 + "-blockdev driver=file,node-name=hda,filename=%s "
1553 + "-device ide-hd,drive=hda,bus=ide.0,unit=0 -incoming defer",
1554 + tmp_path[0]);
1555 + dst = qtest_init(dst_args);
1556 +
1557 + qtest_qmp_assert_success(dst, "{ 'execute': 'migrate-incoming',"
1558 + " 'arguments': { 'uri': %s,"
1559 + " 'exit-on-error': false } }", uri);
1560 + ide_migration_wait(dst, "failed");
1561 +
1562 + qtest_quit(dst);
1563 + unlink(path);
1564 +}
1565 +
1566 static void test_cdrom_pio(void)
1567 {
1568 cdrom_read_impl(1, CDROM_PIO);
@@ -1558,6 +1638,7 @@ int main(int argc, char **argv)
1638 qtest_add_func("/ide/migration/chs_translation",
1639 test_migrate_chs_translation);
1640 qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot);
1641 + qtest_add_func("/ide/migration/chs_rejected", test_migrate_chs_rejected);
1642
1643 qtest_add_func("/ide/identify", test_identify);
1644