Bug 1790482 - bitmaps in backing images can't be modified
Summary: bitmaps in backing images can't be modified
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux Advanced Virtualization
Classification: Red Hat
Component: qemu-kvm
Version: 8.1
Hardware: Unspecified
OS: Unspecified
high
unspecified
Target Milestone: rc
: 8.0
Assignee: John Snow
QA Contact: aihua liang
URL:
Whiteboard:
Depends On:
Blocks: 1799009 1799013 1799015
TreeView+ depends on / blocked
 
Reported: 2020-01-13 13:19 UTC by Peter Krempa
Modified: 2020-05-05 09:56 UTC (History)
9 users (show)

Fixed In Version: qemu-kvm-4.2.0-15.module+el8.2.0+6029+618ef2ec
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2020-05-05 09:55:17 UTC
Type: Feature Request
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2020:2017 0 None None None 2020-05-05 09:56:58 UTC

Description Peter Krempa 2020-01-13 13:19:06 UTC
Description of problem:
When attempting to delete/merge block dirty bitmaps residing in backing image which was made read only by a call to blockdev-snapshot fails with 

{"class": "GenericError", "desc": "Bitmap 'a' is readonly and cannot be modified"}}

Version-Release number of selected component (if applicable):
qemu-4.2.0 (upstream)
v4.2.0-609-gdc65a5bdc9 (devel version)


How reproducible:
always

Steps to Reproduce:

The QMP conversation below was recorded when I attempted the following libvirt commands on a fresh VM with an empty image:

$ virsh checkpoint-create-as VM a
Domain checkpoint a created
$ virsh snapshot-create-as --disk-only VM
Domain snapshot 1578918815 created
$ virsh checkpoint-delete VM a
error: Failed to delete checkpoint a
error: internal error: unable to execute QEMU command 'transaction': Bitmap 'a' is readonly and cannot be modified

Note that deletion of bitmaps (checkpoints) across snapshots is not upstream and requires the following patches:

https://www.redhat.com/archives/libvir-list/2020-January/msg00430.html

(I've also rewrapped outputs of query-named-block-nodes in the below log)

2020-01-13 12:26:02.530+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"transaction","arguments":{"actions":[{"type":"block-dirty-bitmap-add","data":{"node":"libvirt-1-format","name":"a","persistent":true,"disabled":false}}]},"id":"libvirt-367"}^M
2020-01-13 12:26:02.532+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-367"}
2020-01-13 12:33:35.396+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"query-named-block-nodes","id":"libvirt-368"}^M
2020-01-13 12:33:35.397+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply=
{
    "return": [
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 10485760,
                "filename": "/tmp/copy4.qcow2",
                "cluster-size": 65536,
                "format": "qcow2",
                "actual-size": 200704,
                "format-specific": {
                    "type": "qcow2",
                    "data": {
                        "compat": "1.1",
                        "lazy-refcounts": false,
                        "refcount-bits": 16,
                        "corrupt": 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,
            "dirty-bitmaps": [
                {
                    "name": "a",
                    "recording": true,
                    "persistent": true,
                    "busy": false,
                    "status": "active",
                    "granularity": 65536,
                    "count": 0
                }
            ],
            "encrypted": false,
            "bps": 0,
            "bps_rd": 0,
            "cache": {
                "no-flush": false,
                "direct": false,
                "writeback": true
            },
            "file": "/tmp/copy4.qcow2",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 197120,
                "filename": "/tmp/copy4.qcow2",
                "format": "file",
                "actual-size": 200704,
                "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/copy4.qcow2",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 520032256,
                "filename": "/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso",
                "format": "raw",
                "actual-size": 520040448,
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": true,
            "node-name": "libvirt-2-format",
            "backing_file_depth": 0,
            "drv": "raw",
            "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-x86-4.9.5.iso",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 520032256,
                "filename": "/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso",
                "format": "file",
                "actual-size": 520040448,
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": false,
            "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-x86-4.9.5.iso",
            "encryption_key_missing": false
        }
    ],
    "id": "libvirt-368"
}
2020-01-13 12:33:35.397+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"blockdev-add","arguments":{"driver":"file","filename":"/tmp/copy4.1578918815","node-name":"libvirt-3-storage","auto-read-only":true,"discard":"unmap"},"id":"libvirt-369"}^M
2020-01-13 12:33:35.399+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-369"}
2020-01-13 12:33:35.399+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"blockdev-create","arguments":{"job-id":"create-libvirt-3-format","options":{"driver":"qcow2","file":"libvirt-3-storage","size":10485760,"backing-file":"/tmp/copy4.qcow2","backing-fmt":"qcow2"}},"id":"libvirt-370"}^M
2020-01-13 12:33:35.401+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 401136}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.401+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 401163}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.401+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-370"}
2020-01-13 12:33:35.403+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 403033}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.403+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 403057}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.403+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 403076}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.403+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"query-jobs","id":"libvirt-371"}^M
2020-01-13 12:33:35.403+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": [{"current-progress": 1, "status": "concluded", "total-progress": 1, "type": "create", "id": "create-libvirt-3-format"}], "id": "libvirt-371"}
2020-01-13 12:33:35.403+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"job-dismiss","arguments":{"id":"create-libvirt-3-format"},"id":"libvirt-372"}^M
2020-01-13 12:33:35.404+0000: 3311890: info : qemuMonitorJSONIOProcessLine:234 : QEMU_MONITOR_RECV_EVENT: mon=0x7fffd8310fa0 event={"timestamp": {"seconds": 1578918815, "microseconds": 404341}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "create-libvirt-3-format"}}
2020-01-13 12:33:35.404+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-372"}
2020-01-13 12:33:35.414+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"blockdev-add","arguments":{"node-name":"libvirt-3-format","read-only":false,"driver":"qcow2","file":"libvirt-3-storage","backing":null},"id":"libvirt-373"}^M
2020-01-13 12:33:35.418+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-373"}
2020-01-13 12:33:35.418+0000: 3311896: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"transaction","arguments":{"actions":[{"type":"block-dirty-bitmap-add","data":{"node":"libvirt-3-format","name":"a","persistent":true,"disabled":false,"granularity":65536}},{"type":"blockdev-snapshot","data":{"node":"libvirt-1-format","overlay":"libvirt-3-format"}}]},"id":"libvirt-374"}^M
2020-01-13 12:33:35.425+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"return": {}, "id": "libvirt-374"}
2020-01-13 12:33:43.976+0000: 3311897: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"query-named-block-nodes","id":"libvirt-375"}^M
2020-01-13 12:33:43.978+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply=
{
    "return": [
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "backing-image": {
                    "virtual-size": 10485760,
                    "filename": "/tmp/copy4.qcow2",
                    "cluster-size": 65536,
                    "format": "qcow2",
                    "actual-size": 208896,
                    "format-specific": {
                        "type": "qcow2",
                        "data": {
                            "compat": "1.1",
                            "lazy-refcounts": false,
                            "bitmaps": [
                                {
                                    "flags": [
                                        "auto"
                                    ],
                                    "name": "a",
                                    "granularity": 65536
                                }
                            ],
                            "refcount-bits": 16,
                            "corrupt": false
                        }
                    },
                    "dirty-flag": false
                },
                "backing-filename-format": "qcow2",
                "virtual-size": 10485760,
                "filename": "/tmp/copy4.1578918815",
                "cluster-size": 65536,
                "format": "qcow2",
                "actual-size": 200704,
                "format-specific": {
                    "type": "qcow2",
                    "data": {
                        "compat": "1.1",
                        "lazy-refcounts": false,
                        "refcount-bits": 16,
                        "corrupt": false
                    }
                },
                "full-backing-filename": "/tmp/copy4.qcow2",
                "backing-filename": "/tmp/copy4.qcow2",
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": false,
            "node-name": "libvirt-3-format",
            "backing_file_depth": 1,
            "drv": "qcow2",
            "iops": 0,
            "bps_wr": 0,
            "write_threshold": 0,
            "backing_file": "/tmp/copy4.qcow2",
            "dirty-bitmaps": [
                {
                    "name": "a",
                    "recording": true,
                    "persistent": true,
                    "busy": false,
                    "status": "active",
                    "granularity": 65536,
                    "count": 0
                }
            ],
            "encrypted": false,
            "bps": 0,
            "bps_rd": 0,
            "cache": {
                "no-flush": false,
                "direct": false,
                "writeback": true
            },
            "file": "/tmp/copy4.1578918815",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 197120,
                "filename": "/tmp/copy4.1578918815",
                "format": "file",
                "actual-size": 200704,
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": false,
            "node-name": "libvirt-3-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/copy4.1578918815",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 10485760,
                "filename": "/tmp/copy4.qcow2",
                "cluster-size": 65536,
                "format": "qcow2",
                "actual-size": 208896,
                "format-specific": {
                    "type": "qcow2",
                    "data": {
                        "compat": "1.1",
                        "lazy-refcounts": false,
                        "bitmaps": [
                            {
                                "flags": [
                                    "auto"
                                ],
                                "name": "a",
                                "granularity": 65536
                            }
                        ],
                        "refcount-bits": 16,
                        "corrupt": false
                    }
                },
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": true,
            "node-name": "libvirt-1-format",
            "backing_file_depth": 0,
            "drv": "qcow2",
            "iops": 0,
            "bps_wr": 0,
            "write_threshold": 0,
            "dirty-bitmaps": [
                {
                    "name": "a",
                    "recording": true,
                    "persistent": true,
                    "busy": false,
                    "status": "active",
                    "granularity": 65536,
                    "count": 0
                }
            ],
            "encrypted": false,
            "bps": 0,
            "bps_rd": 0,
            "cache": {
                "no-flush": false,
                "direct": false,
                "writeback": true
            },
            "file": "/tmp/copy4.qcow2",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 328192,
                "filename": "/tmp/copy4.qcow2",
                "format": "file",
                "actual-size": 208896,
                "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/copy4.qcow2",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 520032256,
                "filename": "/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso",
                "format": "raw",
                "actual-size": 520040448,
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": true,
            "node-name": "libvirt-2-format",
            "backing_file_depth": 0,
            "drv": "raw",
            "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-x86-4.9.5.iso",
            "encryption_key_missing": false
        },
        {
            "iops_rd": 0,
            "detect_zeroes": "off",
            "image": {
                "virtual-size": 520032256,
                "filename": "/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso",
                "format": "file",
                "actual-size": 520040448,
                "dirty-flag": false
            },
            "iops_wr": 0,
            "ro": false,
            "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-x86-4.9.5.iso",
            "encryption_key_missing": false
        }
    ],
    "id": "libvirt-375"
}

2020-01-13 12:33:43.979+0000: 3311897: info : qemuMonitorSend:993 : QEMU_MONITOR_SEND_MSG: mon=0x7fffd8310fa0 msg={"execute":"transaction","arguments":{"actions":[{"type":"block-dirty-bitmap-remove","data":{"node":"libvirt-3-format","name":"a"}},{"type":"block-dirty-bitmap-remove","data":{"node":"libvirt-1-format","name":"a"}}]},"id":"libvirt-376"}^M
2020-01-13 12:33:43.981+0000: 3311890: info : qemuMonitorJSONIOProcessLine:239 : QEMU_MONITOR_RECV_REPLY: mon=0x7fffd8310fa0 reply={"id": "libvirt-376", "error": {"class": "GenericError", "desc": "Bitmap 'a' is readonly and cannot be modified"}}



Actual results:
Error is reported.

Expected results: 
QEMU reopens the backing file read-write and deletes the bitmap. Libvirt grants qemu selinux permissions to do it prior to attempting the transaction.

Additional info:

Comment 1 Ademar Reis 2020-02-05 23:12:31 UTC
QEMU has been recently split into sub-components and as a one-time operation to avoid breakage of tools, we are setting the QEMU sub-component of this BZ to "General". Please review and change the sub-component if necessary the next time you review this BZ. Thanks

Comment 7 Yash Mankad 2020-03-13 18:51:02 UTC
Granting pm_ack+

@Aihua, could you kindly grant qa_ack+ ?

Comment 12 aihua liang 2020-03-18 02:59:52 UTC
Hi, 
  
Test on qemu-kvm-4.2.0-15.module+el8.2.0+6029+618ef2ec, still hit this issue.

Test Steps:
 1. Start guest with qemu cmds:
     /usr/libexec/qemu-kvm \
    -name 'avocado-vt-vm1'  \
    -sandbox on  \
    -machine q35  \
    -nodefaults \
    -device VGA,bus=pcie.0,addr=0x1 \
    -m 4096  \
    -smp 16,maxcpus=16,cores=8,threads=1,dies=1,sockets=2  \
    -cpu 'EPYC',+kvm_pv_unhalt  \
    -chardev socket,id=qmp_id_qmpmonitor1,path=/var/tmp/monitor-qmpmonitor1-20200203-033416-61dmcn92,server,nowait \
    -mon chardev=qmp_id_qmpmonitor1,mode=control  \
    -chardev socket,id=qmp_id_catch_monitor,path=/var/tmp/monitor-catch_monitor-20200203-033416-61dmcn92,server,nowait \
    -mon chardev=qmp_id_catch_monitor,mode=control \
    -device pvpanic,ioport=0x505,id=idy8YPXp \
    -chardev socket,path=/var/tmp/serial-serial0-20200203-033416-61dmcn92,server,nowait,id=chardev_serial0 \
    -device isa-serial,id=serial0,chardev=chardev_serial0  \
    -chardev socket,id=seabioslog_id_20200203-033416-61dmcn92,path=/var/tmp/seabios-20200203-033416-61dmcn92,server,nowait \
    -device isa-debugcon,chardev=seabioslog_id_20200203-033416-61dmcn92,iobase=0x402 \
    -device pcie-root-port,id=pcie.0-root-port-2,slot=2,chassis=2,addr=0x2,bus=pcie.0 \
    -device qemu-xhci,id=usb1,bus=pcie.0-root-port-2,addr=0x0 \
    -object iothread,id=iothread0 \
    -device pcie-root-port,id=pcie.0-root-port-3,slot=3,chassis=3,addr=0x3,bus=pcie.0 \
    -blockdev node-name=file_image1,driver=file,aio=threads,filename=/home/kvm_autotest_root/images/rhel820-64-virtio-scsi.qcow2,cache.direct=on,cache.no-flush=off \
    -blockdev node-name=drive_image1,driver=qcow2,cache.direct=on,cache.no-flush=off,file=file_image1 \
    -device virtio-blk-pci,id=image1,drive=drive_image1,write-cache=on,bus=pcie.0-root-port-3,iothread=iothread0 \
    -device pcie-root-port,id=pcie.0-root-port-6,slot=6,chassis=6,addr=0x6,bus=pcie.0 \
    -blockdev node-name=file_data1,driver=file,aio=threads,filename=/home/data.qcow2,cache.direct=on,cache.no-flush=off \
    -blockdev node-name=drive_data1,driver=qcow2,cache.direct=on,cache.no-flush=off,file=file_data1 \
    -device virtio-blk-pci,id=data1,drive=drive_data1,write-cache=on,bus=pcie.0-root-port-6 \
    -device pcie-root-port,id=pcie.0-root-port-4,slot=4,chassis=4,addr=0x4,bus=pcie.0 \
    -device virtio-net-pci,mac=9a:6c:ca:b7:36:85,id=idz4QyVp,netdev=idNnpx5D,bus=pcie.0-root-port-4,addr=0x0  \
    -netdev tap,id=idNnpx5D,vhost=on \
    -device usb-tablet,id=usb-tablet1,bus=usb1.0,port=1  \
    -vnc :0  \
    -rtc base=utc,clock=host,driftfix=slew  \
    -boot menu=off,order=cdn,once=c,strict=off \
    -enable-kvm \
    -device pcie-root-port,id=pcie_extra_root_port_0,slot=5,chassis=5,addr=0x5,bus=pcie.0 \
    -monitor stdio \
    -qmp tcp:0:3000,server,nowait \

 2. Add a persistent bitmap to drive_image1
     { "execute": "block-dirty-bitmap-add", "arguments": {"node": "drive_image1", "name": "bitmap0","persistent":true}}
  
 3. Create snapshot target: sn1 and do snapshot from drive_image1 to sn1
     {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn1','size':21474836480},'job-id':'job1'}}
     {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn1','filename':'/root/sn1'}}
     {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn1','size':21474836480},'job-id':'job2'}}
     {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn1','file':'drive_sn1'}}
     {'execute':'job-dismiss','arguments':{'id':'job1'}}
     {'execute':'job-dismiss','arguments':{'id':'job2'}}
     {"execute":"blockdev-snapshot","arguments":{"node":"drive_image1","overlay":"sn1"}}

 4. Add persistent bitmap to sn1
     { "execute": "block-dirty-bitmap-add", "arguments": {"node": "sn1", "name": "bitmap0","persistent":true}}

 5. Remove bitmaps in snapshot node and its backing node
     { "execute": "transaction", "arguments": { "actions": [ {"type": "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},{"type": "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
{"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly and cannot be modified"}}

Comment 13 Peter Krempa 2020-03-18 07:01:40 UTC
The intended use of this is that after the 'blockdev-snapshot' step, you use 'x-blockdev-reopen' to reopen the format layer read-write ({'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':'sn1', "read-only":false,'file':'drive_sn1'}} and then do the bitmap modifications. The bitmaps can't be modified without the reopen step and libvirt is actually intending to use it like this.

Comment 14 aihua liang 2020-03-18 10:17:31 UTC
(In reply to Peter Krempa from comment #13)
> The intended use of this is that after the 'blockdev-snapshot' step, you use
> 'x-blockdev-reopen' to reopen the format layer read-write
> ({'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':
> 'sn1', "read-only":false,'file':'drive_sn1'}} and then do the bitmap
> modifications. The bitmaps can't be modified without the reopen step and
> libvirt is actually intending to use it like this.

Hi,Peter

 When execute x-blockdev-reopen after snapshot, error appears:
{"execute":"blockdev-snapshot","arguments":{"node":"drive_image1","overlay":"sn1"}}
{'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':'sn1', "read-only":false,'file':'drive_sn1'}}
{"error": {"class": "GenericError", "desc": "backing is missing for 'sn1'"}}

 Even if i use cmd:
  {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':'sn1', "read-only":false,'file':'drive_sn1','backing':'drive_image1'}}
 then remove bitmap still fail:
   { "execute": "transaction", "arguments": { "actions": [ {"type": "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},{"type": "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
{"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly and cannot be modified"}}

 What confusing me is that:
  After we do snapshot, overlay:sn1 is opened with rw, and its backing file:drive_image1 was opened with ro. If we delete the bitmap of the backing chain, it will fail for readonly limitation.
  {"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly and cannot be modified"}}

  So if we want to delete bitmap of backing chain, i think, we should reopen the backing chain with rw, so the correct operation should be:
  {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':'drive_image1', "read-only":false,'file':'file_image1'}}
  then delete bitmaps:
    { "execute": "transaction", "arguments": { "actions": [ {"type": "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},{"type": "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
{"return": {}}
   and it works in fact.

 Not sure what's the correct test steps, please help to confirm.
 And under what scenario that we need to reopen the backing nodes and modify/delete their bitmaps?

BR,
Aliang

Comment 15 Peter Krempa 2020-03-18 10:24:16 UTC
(In reply to aihua liang from comment #14)
> (In reply to Peter Krempa from comment #13)
> > The intended use of this is that after the 'blockdev-snapshot' step, you use
> > 'x-blockdev-reopen' to reopen the format layer read-write
> > ({'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':
> > 'sn1', "read-only":false,'file':'drive_sn1'}} and then do the bitmap
> > modifications. The bitmaps can't be modified without the reopen step and
> > libvirt is actually intending to use it like this.
> 
> Hi,Peter
> 
>  When execute x-blockdev-reopen after snapshot, error appears:
> {"execute":"blockdev-snapshot","arguments":{"node":"drive_image1","overlay":
> "sn1"}}
> {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':
> 'sn1', "read-only":false,'file':'drive_sn1'}}
> {"error": {"class": "GenericError", "desc": "backing is missing for 'sn1'"}}
> 
>  Even if i use cmd:
>  
> {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':
> 'sn1', "read-only":false,'file':'drive_sn1','backing':'drive_image1'}}
>  then remove bitmap still fail:
>    { "execute": "transaction", "arguments": { "actions": [ {"type":
> "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},
> {"type":
> "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
> {"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly
> and cannot be modified"}}
> 
>  What confusing me is that:
>   After we do snapshot, overlay:sn1 is opened with rw, and its backing
> file:drive_image1 was opened with ro. If we delete the bitmap of the backing
> chain, it will fail for readonly limitation.
>   {"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly
> and cannot be modified"}}

Yes, you are completely correct. I gave a wrong example.

>   So if we want to delete bitmap of backing chain, i think, we should reopen
> the backing chain with rw, so the correct operation should be:

Yes exactly. The backing chain needs to be reopened.

> {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':
> 'drive_image1', "read-only":false,'file':'file_image1'}}
>   then delete bitmaps:
>     { "execute": "transaction", "arguments": { "actions": [ {"type":
> "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},
> {"type":
> "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
> {"return": {}}
>    and it works in fact.
> 
>  Not sure what's the correct test steps, please help to confirm.
>  And under what scenario that we need to reopen the backing nodes and
> modify/delete their bitmaps?

The steps you've done are in fact correct and it's what libvirt is using. Sorry for the confusion in my original comment.

Comment 16 aihua liang 2020-03-18 10:42:34 UTC
Test on qemu-kvm-4.2.0-15.module+el8.2.0+6029+618ef2ec, it works ok after x-blockdev-reopen the backing chain.

Test Steps:
 1. Start guest with qemu cmds:
     /usr/libexec/qemu-kvm \
    -name 'avocado-vt-vm1'  \
    -sandbox on  \
    -machine q35  \
    -nodefaults \
    -device VGA,bus=pcie.0,addr=0x1 \
    -m 4096  \
    -smp 16,maxcpus=16,cores=8,threads=1,dies=1,sockets=2  \
    -cpu 'EPYC',+kvm_pv_unhalt  \
    -chardev socket,id=qmp_id_qmpmonitor1,path=/var/tmp/monitor-qmpmonitor1-20200203-033416-61dmcn92,server,nowait \
    -mon chardev=qmp_id_qmpmonitor1,mode=control  \
    -chardev socket,id=qmp_id_catch_monitor,path=/var/tmp/monitor-catch_monitor-20200203-033416-61dmcn92,server,nowait \
    -mon chardev=qmp_id_catch_monitor,mode=control \
    -device pvpanic,ioport=0x505,id=idy8YPXp \
    -chardev socket,path=/var/tmp/serial-serial0-20200203-033416-61dmcn92,server,nowait,id=chardev_serial0 \
    -device isa-serial,id=serial0,chardev=chardev_serial0  \
    -chardev socket,id=seabioslog_id_20200203-033416-61dmcn92,path=/var/tmp/seabios-20200203-033416-61dmcn92,server,nowait \
    -device isa-debugcon,chardev=seabioslog_id_20200203-033416-61dmcn92,iobase=0x402 \
    -device pcie-root-port,id=pcie.0-root-port-2,slot=2,chassis=2,addr=0x2,bus=pcie.0 \
    -device qemu-xhci,id=usb1,bus=pcie.0-root-port-2,addr=0x0 \
    -object iothread,id=iothread0 \
    -device pcie-root-port,id=pcie.0-root-port-3,slot=3,chassis=3,addr=0x3,bus=pcie.0 \
    -blockdev node-name=file_image1,driver=file,aio=threads,filename=/home/kvm_autotest_root/images/rhel820-64-virtio-scsi.qcow2,cache.direct=on,cache.no-flush=off \
    -blockdev node-name=drive_image1,driver=qcow2,cache.direct=on,cache.no-flush=off,file=file_image1 \
    -device virtio-blk-pci,id=image1,drive=drive_image1,write-cache=on,bus=pcie.0-root-port-3,iothread=iothread0 \
    -device pcie-root-port,id=pcie.0-root-port-6,slot=6,chassis=6,addr=0x6,bus=pcie.0 \
    -blockdev node-name=file_data1,driver=file,aio=threads,filename=/home/data.qcow2,cache.direct=on,cache.no-flush=off \
    -blockdev node-name=drive_data1,driver=qcow2,cache.direct=on,cache.no-flush=off,file=file_data1 \
    -device virtio-blk-pci,id=data1,drive=drive_data1,write-cache=on,bus=pcie.0-root-port-6 \
    -device pcie-root-port,id=pcie.0-root-port-4,slot=4,chassis=4,addr=0x4,bus=pcie.0 \
    -device virtio-net-pci,mac=9a:6c:ca:b7:36:85,id=idz4QyVp,netdev=idNnpx5D,bus=pcie.0-root-port-4,addr=0x0  \
    -netdev tap,id=idNnpx5D,vhost=on \
    -device usb-tablet,id=usb-tablet1,bus=usb1.0,port=1  \
    -vnc :0  \
    -rtc base=utc,clock=host,driftfix=slew  \
    -boot menu=off,order=cdn,once=c,strict=off \
    -enable-kvm \
    -device pcie-root-port,id=pcie_extra_root_port_0,slot=5,chassis=5,addr=0x5,bus=pcie.0 \
    -monitor stdio \
    -qmp tcp:0:3000,server,nowait \

 2. Add persistent bitmap to drive_image1
     { "execute": "block-dirty-bitmap-add", "arguments": {"node": "drive_image1", "name": "bitmap0","persistent":true}}

 3. Create snapshot target: sn1 and do snapshot from drive_image1 to sn1
     {'execute':'blockdev-create','arguments':{'options': {'driver':'file','filename':'/root/sn1','size':21474836480},'job-id':'job1'}}
     {'execute':'blockdev-add','arguments':{'driver':'file','node-name':'drive_sn1','filename':'/root/sn1'}}
     {'execute':'blockdev-create','arguments':{'options': {'driver': 'qcow2','file':'drive_sn1','size':21474836480},'job-id':'job2'}}
     {'execute':'blockdev-add','arguments':{'driver':'qcow2','node-name':'sn1','file':'drive_sn1'}}
     {'execute':'job-dismiss','arguments':{'id':'job1'}}
     {'execute':'job-dismiss','arguments':{'id':'job2'}}
     {"execute":"blockdev-snapshot","arguments":{"node":"drive_image1","overlay":"sn1"}}

 4. Add persistent bitmap to sn1
     { "execute": "block-dirty-bitmap-add", "arguments": {"node": "sn1", "name": "bitmap0","persistent":true}}

 5. Reopen backing image.
     {'execute':'x-blockdev-reopen','arguments':{'driver':'qcow2','node-name':'drive_image1', "read-only":false,'file':'file_image1'}}

 6. { "execute": "transaction", "arguments": { "actions": [ {"type": "block-dirty-bitmap-remove","data":{"node":"drive_image1","name":"bitmap0"}},{"type": "block-dirty-bitmap-remove","data":{"node":"sn1","name":"bitmap0"}}]}}
{"return": {}}

Comment 17 John Snow 2020-03-18 21:21:09 UTC
Closing my robot-set needinfo as this is already verified (Thanks to Peter and Kevin.)

Justifications for inclusion are no longer required.

Comment 18 aihua liang 2020-03-19 01:39:17 UTC
(In reply to John Snow from comment #17)
> Closing my robot-set needinfo as this is already verified (Thanks to Peter
> and Kevin.)
> 
> Justifications for inclusion are no longer required.

Although have verified this bug, but still can't imagine under what scenario we will need to delete/modify the bitmaps of backing chain.

Hi, John

 Do you know this scenario? 

BR,
Aliang

Comment 19 John Snow 2020-03-19 20:08:31 UTC
(In reply to aihua liang from comment #18)
> (In reply to John Snow from comment #17)
> > Closing my robot-set needinfo as this is already verified (Thanks to Peter
> > and Kevin.)
> > 
> > Justifications for inclusion are no longer required.
> 
> Although have verified this bug, but still can't imagine under what scenario
> we will need to delete/modify the bitmaps of backing chain.
> 
> Hi, John
> 
>  Do you know this scenario? 
> 
> BR,
> Aliang

We may want to DISABLE bitmaps in a backing file to prevent them from being dirtied during a commit operation. Normally, I advocated disabling them in the backing file before creating the snapshot. However, if a snapshot is created outside of libvirt (or the API user forgot to disable them in advance), they will be dirtied by the commit.

Being able to disable backing bitmaps, in particular, avoids this problem.

--js

Comment 20 aihua liang 2020-03-23 02:34:09 UTC
(In reply to John Snow from comment #19)
> (In reply to aihua liang from comment #18)
> > (In reply to John Snow from comment #17)
> > > Closing my robot-set needinfo as this is already verified (Thanks to Peter
> > > and Kevin.)
> > > 
> > > Justifications for inclusion are no longer required.
> > 
> > Although have verified this bug, but still can't imagine under what scenario
> > we will need to delete/modify the bitmaps of backing chain.
> > 
> > Hi, John
> > 
> >  Do you know this scenario? 
> > 
> > BR,
> > Aliang
> 
> We may want to DISABLE bitmaps in a backing file to prevent them from being
> dirtied during a commit operation. Normally, I advocated disabling them in
> the backing file before creating the snapshot. However, if a snapshot is
> created outside of libvirt (or the API user forgot to disable them in
> advance), they will be dirtied by the commit.
> 
> Being able to disable backing bitmaps, in particular, avoids this problem.
> 
> --js

Hi, John

 If we do a live commit on disabled bitmaps, will the bitmaps merged automatically?
 From my test, the answer is 'no'.
   base(file0, bitmap0)  --> sn1 (file1, bitmap1) --> sn2 (file2, bitmap2) --> sn3 (file3 , bitmap3)  -- all bitmaps are disabled before snapshot creation.
   then i do live commit from sn3->base.  
     base(file0, file1, file2, file3, bitmap0)  -- count of bitmap0 not changed which means data incremental of file1,file2 and file3 not recorded by bitmap0, that seems unreasonable.

 But if i don't disable bitmaps before snapshot creation.
   After same commit operation with above, you can see that count of bitmap0 changed automatically with bitmap1,bitmap2 and bitmap3 not changed, which looks more reasonable.

BR,
Aliang

Comment 21 Peter Krempa 2020-03-23 07:59:55 UTC
The bitmap merging on commit is done via explicit QMP calls in the commit job handling in libvirt.

Comment 22 aihua liang 2020-03-23 08:42:29 UTC
(In reply to Peter Krempa from comment #21)
> The bitmap merging on commit is done via explicit QMP calls in the commit
> job handling in libvirt.

Hi, Peter
 
  Can you help to introduce how it works?

Thanks,
Aliang

Comment 23 Peter Krempa 2020-03-24 08:30:23 UTC
So a high-level look on what we do is:

1) all active bitmaps in the base of the commit are disabled
2) block commit is started  (with auto-dismiss set to false)
3) wait until the job concludes
4) we then calculate the necessary bitmap merge (libvirt creates bitmaps with the same name as any active bitmap in the in the overlay when doing a snapshot) and instruct qemu to merge all bitmaps with the same name between top and base of the job
5) images obsoleted by the commit are then blockdev-deleted

Comment 28 errata-xmlrpc 2020-05-05 09:55:17 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2020:2017


Note You need to log in before you can comment on or make changes to this bug.