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:
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
Granting pm_ack+ @Aihua, could you kindly grant qa_ack+ ?
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"}}
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.
(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
(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.
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": {}}
Closing my robot-set needinfo as this is already verified (Thanks to Peter and Kevin.) Justifications for inclusion are no longer required.
(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
(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
(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
The bitmap merging on commit is done via explicit QMP calls in the commit job handling in libvirt.
(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
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
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