qemu: monitor: Store internal snapshot names from 'query-named-block-nodes'

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@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Peter Krempa 2024-10-02 14:24:31 +02:00
parent 9df1453db8
commit 6d8ae98fa0
5 changed files with 334 additions and 0 deletions

View File

@ -709,6 +709,9 @@ struct _qemuBlockNamedNodeData {
qemuBlockNamedNodeDataBitmap **bitmaps; qemuBlockNamedNodeDataBitmap **bitmaps;
size_t nbitmaps; size_t nbitmaps;
/* NULL terminated string list of internal snapshot names */
char **snapshots;
/* the cluster size of the image is valid only when > 0 */ /* the cluster size of the image is valid only when > 0 */
unsigned long long clusterSize; unsigned long long clusterSize;

View File

@ -2569,6 +2569,7 @@ qemuMonitorJSONBlockNamedNodeDataFree(qemuBlockNamedNodeData *data)
for (i = 0; i < data->nbitmaps; i++) for (i = 0; i < data->nbitmaps; i++)
qemuMonitorJSONBlockNamedNodeDataBitmapFree(data->bitmaps[i]); qemuMonitorJSONBlockNamedNodeDataBitmapFree(data->bitmaps[i]);
g_strfreev(data->snapshots);
g_free(data->bitmaps); g_free(data->bitmaps);
g_free(data); g_free(data);
} }
@ -2631,6 +2632,7 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED,
GHashTable *nodes = opaque; GHashTable *nodes = opaque;
virJSONValue *img; virJSONValue *img;
virJSONValue *bitmaps; virJSONValue *bitmaps;
virJSONValue *snapshots;
virJSONValue *format_specific; virJSONValue *format_specific;
const char *nodename; const char *nodename;
g_autoptr(qemuBlockNamedNodeData) ent = NULL; g_autoptr(qemuBlockNamedNodeData) ent = NULL;
@ -2654,6 +2656,24 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED,
if ((bitmaps = virJSONValueObjectGetArray(val, "dirty-bitmaps"))) if ((bitmaps = virJSONValueObjectGetArray(val, "dirty-bitmaps")))
qemuMonitorJSONBlockGetNamedNodeDataBitmaps(bitmaps, ent); 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 */ /* query qcow2 format specific props */
if ((format_specific = virJSONValueObjectGetObject(img, "format-specific")) && if ((format_specific = virJSONValueObjectGetObject(img, "format-specific")) &&
STREQ_NULLABLE(virJSONValueObjectGetString(format_specific, "type"), "qcow2")) { STREQ_NULLABLE(virJSONValueObjectGetString(format_specific, "type"), "qcow2")) {

View File

@ -594,6 +594,15 @@ testQemuDetectBitmapsWorker(GHashTable *nodedata,
bitmap->granularity, bitmap->dirtybytes); 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); virBufferAdjustIndent(buf, -1);
} }
@ -1201,6 +1210,7 @@ mymain(void)
TEST_IMAGE_CREATE("network-rbd-qcow2", NULL); TEST_IMAGE_CREATE("network-rbd-qcow2", NULL);
TEST_IMAGE_CREATE("network-ssh-qcow2", NULL); TEST_IMAGE_CREATE("network-ssh-qcow2", NULL);
/* The following group also tests internal snapshot detection */
#define TEST_BITMAP_DETECT(testname) \ #define TEST_BITMAP_DETECT(testname) \
do { \ do { \
if (virTestRun("bitmap detect " testname, \ if (virTestRun("bitmap detect " testname, \
@ -1213,6 +1223,7 @@ mymain(void)
TEST_BITMAP_DETECT("basic"); TEST_BITMAP_DETECT("basic");
TEST_BITMAP_DETECT("snapshots"); TEST_BITMAP_DETECT("snapshots");
TEST_BITMAP_DETECT("synthetic"); TEST_BITMAP_DETECT("synthetic");
TEST_BITMAP_DETECT("snapshots-internal");
#define TEST_BACKUP_BITMAP_CALCULATE(testname, source, incrbackup, named) \ #define TEST_BACKUP_BITMAP_CALCULATE(testname, source, incrbackup, named) \
do { \ do { \

View File

@ -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"
}
]

View File

@ -0,0 +1,2 @@
libvirt-1-format:
internal snapshots: '1727868651' '1727872064'