Store the names of internal snapshots present in supported images in the data we dump from 'query-named-block-nodes' so that the upcoming changes to the internal snapshot code can access it. To test this we use the bitmap detection test cases which can be easily extended to dump this data. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 19 ++ tests/qemublocktest.c | 11 + .../bitmap/snapshots-internal.json | 298 ++++++++++++++++++ .../bitmap/snapshots-internal.out | 2 + 5 files changed, 333 insertions(+) create mode 100644 tests/qemublocktestdata/bitmap/snapshots-internal.json create mode 100644 tests/qemublocktestdata/bitmap/snapshots-internal.out diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 6251f48d28..4341519cfe 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -709,6 +709,9 @@ struct _qemuBlockNamedNodeData { qemuBlockNamedNodeDataBitmap **bitmaps; size_t nbitmaps; + /* NULL terminated string list of internal snapshot names */ + char **snapshots; + /* the cluster size of the image is valid only when > 0 */ unsigned long long clusterSize; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 27f74181f6..2c3fce9002 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2631,6 +2631,7 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED, GHashTable *nodes = opaque; virJSONValue *img; virJSONValue *bitmaps; + virJSONValue *snapshots; virJSONValue *format_specific; const char *nodename; g_autoptr(qemuBlockNamedNodeData) ent = NULL; @@ -2654,6 +2655,24 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED, if ((bitmaps = virJSONValueObjectGetArray(val, "dirty-bitmaps"))) qemuMonitorJSONBlockGetNamedNodeDataBitmaps(bitmaps, ent); + if ((snapshots = virJSONValueObjectGetArray(img, "snapshots"))) { + size_t nsnapshots = virJSONValueArraySize(snapshots); + size_t nsnapnames = 0; + size_t i; + + ent->snapshots = g_new0(char *, nsnapshots + 1); + + for (i = 0; i < nsnapshots; i++) { + virJSONValue *snapshot = virJSONValueArrayGet(snapshots, i); + const char *name = virJSONValueObjectGetString(snapshot, "name"); + + if (!name) + continue; + + ent->snapshots[nsnapnames++] = g_strdup(name); + } + } + /* query qcow2 format specific props */ if ((format_specific = virJSONValueObjectGetObject(img, "format-specific")) && STREQ_NULLABLE(virJSONValueObjectGetString(format_specific, "type"), "qcow2")) { diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index 6c4e735466..60ac929e68 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -594,6 +594,15 @@ testQemuDetectBitmapsWorker(GHashTable *nodedata, bitmap->granularity, bitmap->dirtybytes); } + if (data->snapshots) { + char **sn; + + virBufferAddLit(buf, "internal snapshots:"); + + for (sn = data->snapshots; *sn; sn++) + virBufferAsprintf(buf, " '%s'", *sn); + } + virBufferAdjustIndent(buf, -1); } @@ -1201,6 +1210,7 @@ mymain(void) TEST_IMAGE_CREATE("network-rbd-qcow2", NULL); TEST_IMAGE_CREATE("network-ssh-qcow2", NULL); + /* The following group also tests internal snapshot detection */ #define TEST_BITMAP_DETECT(testname) \ do { \ if (virTestRun("bitmap detect " testname, \ @@ -1213,6 +1223,7 @@ mymain(void) TEST_BITMAP_DETECT("basic"); TEST_BITMAP_DETECT("snapshots"); TEST_BITMAP_DETECT("synthetic"); + TEST_BITMAP_DETECT("snapshots-internal"); #define TEST_BACKUP_BITMAP_CALCULATE(testname, source, incrbackup, named) \ do { \ diff --git a/tests/qemublocktestdata/bitmap/snapshots-internal.json b/tests/qemublocktestdata/bitmap/snapshots-internal.json new file mode 100644 index 0000000000..2198f8f364 --- /dev/null +++ b/tests/qemublocktestdata/bitmap/snapshots-internal.json @@ -0,0 +1,298 @@ +[ + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "snapshots": [ + { + "vm-clock-nsec": 992826708, + "name": "1727868651", + "date-sec": 1727868651, + "date-nsec": 317899000, + "vm-clock-sec": 466, + "id": "1", + "vm-state-size": 57440493 + }, + { + "vm-clock-nsec": 159450672, + "name": "1727872064", + "date-sec": 1727872064, + "date-nsec": 991275000, + "vm-clock-sec": 2431, + "id": "2", + "vm-state-size": 57342213 + } + ], + "virtual-size": 104857600, + "filename": "/tmp/internal-snaps.qcow2", + "cluster-size": 65536, + "format": "qcow2", + "actual-size": 115228672, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "compression-type": "zlib", + "lazy-refcounts": false, + "refcount-bits": 16, + "corrupt": false, + "extended-l2": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "node-name": "libvirt-1-format", + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/tmp/internal-snaps.qcow2" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 115409408, + "filename": "/tmp/internal-snaps.qcow2", + "format": "file", + "actual-size": 115228672, + "format-specific": { + "type": "file", + "data": { + + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "node-name": "libvirt-1-storage", + "backing_file_depth": 0, + "drv": "file", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/tmp/internal-snaps.qcow2" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 708837376, + "filename": "/var/lib/libvirt/images/systemrescuecd-amd64-6.1.2.iso", + "format": "file", + "actual-size": 708841472, + "format-specific": { + "type": "file", + "data": { + + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": true, + "node-name": "libvirt-2-storage", + "backing_file_depth": 0, + "drv": "file", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/var/lib/libvirt/images/systemrescuecd-amd64-6.1.2.iso" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "snapshots": [ + { + "vm-clock-nsec": 992826708, + "name": "1727868651", + "date-sec": 1727868651, + "date-nsec": 317899000, + "vm-clock-sec": 466, + "id": "1", + "vm-state-size": 0 + }, + { + "vm-clock-nsec": 159450672, + "name": "1727872064", + "date-sec": 1727872064, + "date-nsec": 991275000, + "vm-clock-sec": 2431, + "id": "2", + "vm-state-size": 0 + } + ], + "virtual-size": 540672, + "filename": "/var/lib/libvirt/qemu/nvram/int-q35_VARS.qcow2", + "cluster-size": 4096, + "format": "qcow2", + "actual-size": 602112, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "compression-type": "zlib", + "lazy-refcounts": false, + "refcount-bits": 16, + "corrupt": false, + "extended-l2": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "node-name": "libvirt-pflash1-format", + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/var/lib/libvirt/qemu/nvram/int-q35_VARS.qcow2" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 598528, + "filename": "/var/lib/libvirt/qemu/nvram/int-q35_VARS.qcow2", + "format": "file", + "actual-size": 602112, + "format-specific": { + "type": "file", + "data": { + + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "node-name": "libvirt-pflash1-storage", + "backing_file_depth": 0, + "drv": "file", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/var/lib/libvirt/qemu/nvram/int-q35_VARS.qcow2" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 3653632, + "filename": "/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2", + "cluster-size": 4096, + "format": "qcow2", + "actual-size": 3678208, + "format-specific": { + "type": "qcow2", + "data": { + "compat": "1.1", + "compression-type": "zlib", + "lazy-refcounts": false, + "refcount-bits": 16, + "corrupt": false, + "extended-l2": false + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": true, + "node-name": "libvirt-pflash0-format", + "backing_file_depth": 0, + "drv": "qcow2", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2" + }, + { + "iops_rd": 0, + "detect_zeroes": "off", + "image": { + "virtual-size": 3678208, + "filename": "/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2", + "format": "file", + "actual-size": 3678208, + "format-specific": { + "type": "file", + "data": { + + } + }, + "dirty-flag": false + }, + "iops_wr": 0, + "ro": false, + "node-name": "libvirt-pflash0-storage", + "backing_file_depth": 0, + "drv": "file", + "iops": 0, + "bps_wr": 0, + "write_threshold": 0, + "encrypted": false, + "bps": 0, + "bps_rd": 0, + "cache": { + "no-flush": false, + "direct": false, + "writeback": true + }, + "file": "/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2" + } +] diff --git a/tests/qemublocktestdata/bitmap/snapshots-internal.out b/tests/qemublocktestdata/bitmap/snapshots-internal.out new file mode 100644 index 0000000000..f2fb0a1dcc --- /dev/null +++ b/tests/qemublocktestdata/bitmap/snapshots-internal.out @@ -0,0 +1,2 @@ +libvirt-1-format: + internal snapshots: '1727868651' '1727872064' -- 2.46.0