This document discusses the two block primitives blockdev-backup and blockdev-mirror.
The blockdev-backup command allows you to create a point-in-time copy of a disk image chain. Where the point-in-time is when you start the blockdev-backup command.
It is equivalent in functionality to drive-backup, the difference being, blockdev-backup operates at node-level in a Block Driver State (BDS) graph.
As an example, the sequence of actions to create a point-in-time backup of an entire disk image chain, to a target, using blockdev-backup would be:
Given, a disk image chain of depth 1, where image [B] is the active overlay (live QEMU is writing to it):
[A] <-- [B]
The following is the procedure to copy the content from the entire chain to a target image (say, [E]), which has the full content from [A] and [B].
Create the overlay, [B]:
(QEMU) blockdev-snapshot-sync node-name=node-A snapshot-file=b.qcow2 snapshot-node-name=node-B format=qcow2 { "execute": "blockdev-snapshot-sync", "arguments": { "node-name": "node-A", "snapshot-file": "b.qcow2", "format": "qcow2", "snapshot-node-name": "node-B" } }
Create a target image, that will contain the copy:
$ qemu-img create -f qcow2 e.qcow2 39M
Then, add it to QEMU via blockdev-add:
(QEMU) blockdev-add driver=qcow2 node-name=node-E file={"driver":"file","filename":"e.qcow2"} { "execute": "blockdev-add", "arguments": { "node-name": "node-E", "driver": "qcow2", "file": { "driver": "file", "filename": "e.qcow2" } } }
Then, invoke blockdev-backup, to copy the contents from the entire image chain, consisting of images [A], and [B], to the target image 'e.qcow2':
(QEMU) blockdev-backup device=node-B target=node-E sync=full job-id=job0 { "execute": "blockdev-backup", "arguments": { "device": "node-B", "job-id": "job0", "target": "node-E", "sync": "full" } }
Once the above 'backup' operation has completed, an event, BLOCK_JOB_COMPLETED will be emitted, signalling successful completion.
Next, query for any active block device jobs (there should be none):
(QEMU) query-block-jobs { "execute": "query-block-jobs", "arguments": {} }
Shutdown the guest (NB: the following step is really important; if not done, an error, "Failed to get shared "write" lock on e.qcow2", will be thrown when you do qemu-img compare):
(QEMU) quit { "execute": "quit", "arguments": {} } "return": {} } (QEMU) {u'timestamp': {u'seconds': 1496072942, u'microseconds': 685292}, u'event': u'SHUTDOWN'}
The end result will be, the image 'e.qcow2' containing a point-in-time backup of the disk image chain -- i.e. contents from images [A], and [B] at the time the blockdev-backup command was initiated.
One way to confirm the backup disk image contains the identical content with the disk image chain is to compare the backup, and the contents of the chain, you should see "Images are identical". (NB: this is assuming QEMU was launched with -S option, which will not start the CPUs at guest boot up):
$ qemu-img compare b.qcow2 e.qcow2 Warning: Image size mismatch! Images are identical.
NOTE: The "Warning: Image size mismatch!" is expected, as we created the target image (e.qcow2) with 39M size.
The blockdev-mirror command allows you to synchronize a running disk image chain (all or part of it) to a target image.
Once a 'mirror' job has started, there are two possible actions when a drive-mirror job is active:
As an example, the sequence of actions to create a point-in-time backup of an entire disk image chain, to a target, using blockdev-mirror would be:
Given the disk image chain:
[A] <-- [B]
To copy the contents of the entire disk image chain, from [A] all the way to [D], to a new target, call it [E]. The following is the flow.
Create the overlay, [B]:
(QEMU) blockdev-snapshot-sync node-name=node-A snapshot-file=b.qcow2 snapshot-node-name=node-B format=qcow2 { "execute": "blockdev-snapshot-sync", "arguments": { "node-name": "node-A", "snapshot-file": "b.qcow2", "format": "qcow2", "snapshot-node-name": "node-B" } }
Create the target image, [E]:
$ qemu-img create -f qcow2 e.qcow2 39M
Add the above created target image to QEMU, via blockdev-add:
(QEMU) blockdev-add driver=qcow2 node-name=node-E file={"driver":"file","filename":"e.qcow2"} { "execute": "blockdev-add", "arguments": { "node-name": "node-E", "driver": "qcow2", "file": { "driver": "file", "filename": "e.qcow2" } } }
Perform the blockdev-mirror, and observe for the event BLOCK_JOB_READY:
(QEMU) blockdev-mirror device=node-B target=node-E sync=full job-id=job0 { "execute": "blockdev-mirror", "arguments": { "device": "node-D", "job-id": "job0", "target": "node-E", "sync": "full" } }
Query for active block jobs, there should be a 'mirror' job ready:
(QEMU) query-block-jobs { "execute": "query-block-jobs", "arguments": {} } { "return": [ { "busy": false, "type": "mirror", "len": 21561344, "paused": false, "ready": true, "io-status": "ok", "offset": 21561344, "device": "job0", "speed": 0 } ] }
Gracefully complete the block device job operation, and observe for the event BLOCK_JOB_COMPLETED:
(QEMU) block-job-complete device=job0 { "execute": "block-job-complete", "arguments": { "device": "job0" } } { "return": {} }
Shutdown the guest, by issuing the quit QMP command:
(QEMU) quit { "execute": "quit", "arguments": {} }