Note: This is a beta release of Red Hat Bugzilla 5.0. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Also email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback here.
Bug 1062142 - live snapshot merge (commit) of the active layer
Summary: live snapshot merge (commit) of the active layer
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: libvirt
Version: 7.0
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Eric Blake
QA Contact: Virtualization Bugs
URL:
Whiteboard:
: 1148201 (view as bug list)
Depends On: 1041301 1130603
Blocks: 784395 837916 1035038 1002699 1045196 1148201 1150379
TreeView+ depends on / blocked
 
Reported: 2014-02-06 10:04 UTC by Peter Krempa
Modified: 2016-04-26 14:14 UTC (History)
23 users (show)

Fixed In Version: libvirt-1.2.8-1.el7
Doc Type: Bug Fix
Doc Text:
Clone Of: 1041301
: 1148201 (view as bug list)
Environment:
Last Closed: 2015-03-05 07:29:44 UTC
Target Upstream Version:
scohen: needinfo+
scohen: needinfo+
scohen: needinfo+


Attachments (Terms of Use)


Links
System ID Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2015:0323 normal SHIPPED_LIVE Low: libvirt security, bug fix, and enhancement update 2015-03-05 12:10:54 UTC

Description Peter Krempa 2014-02-06 10:04:08 UTC
+++ This bug was initially created as a clone of Bug #1041301 +++

The current implementation of live-merge doesn't work on the active layer. This bug is about fixing it.

For more details about live-merge, check bug 767233

Upstream series from Fam:
http://lists.gnu.org/archive/html/qemu-devel/2013-11/msg03237.html

Comment 1 Peter Krempa 2014-02-06 10:08:11 UTC
blockjob-commit from the active layer requires us to terminate the job with "block-job-complete" after it finishes to pivot from the actual active image

+++ b/qapi-schema.json
@@ -1967,9 +1967,11 @@
 #
 # @top:              The file name of the backing image within the image chain,
 #                    which contains the topmost data to be committed down.
-#                    Note, the active layer as 'top' is currently unsupported.
 #
 #                    If top == base, that is an error.
+#                    If top == active, the job will not be completed by itself,
+#                    user needs to complete the job with the block-job-complete
+#                    command after getting the ready event. (Since 1.8)
 #

Comment 2 Peter Krempa 2014-02-06 10:09:45 UTC
A minor fix to the blockjob commit handling function is needed along with adding the termination step:

commit 5d2691cc4c0b8d64440b072c93f157f641c37a72
Author: Peter Krempa <pkrempa@redhat.com>
Date:   Wed Feb 5 18:40:39 2014 +0100

    qemu: blockjob: Print correct file name in error message
    
    When attempting a blockcommit from the top layer, the base argument
    passed is NULL. This will be dereferenced when attempting a commit with
    an empty image chain. Output the real volume path instead:
    
    virsh blockcommit --verbose --path vda --domain DOMNAME --wait
    error: invalid argument: top '/path/somefile' in chain for 'vda' has no backing file
    
    instead of:
    
    error: invalid argument: top '(null)' in chain for 'vda' has no backing file

Comment 3 Eric Blake 2014-02-12 15:11:51 UTC
I've confirmed that qemu will support active layer commit in 7.0, and will get libvirt working with it as soon as I get a chance

Comment 4 yangyang 2014-02-26 10:40:47 UTC
Reproduced on 
kernel: 3.10.0-95.el7.x86_64
libvirt-1.1.1-24.el7.x86_64

Steps:
 1. Define and start a domain

# virsh dumpxml qtest1

<domain type='kvm' id='15'>
  <name>qtest1</name>
  <uuid>9b76e092-3941-4e36-abf9-ed6817b467dd</uuid>
  <memory unit='KiB'>1048576</memory>
  <currentMemory unit='KiB'>1048576</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/migration/qtest1.img'>
        <seclabel model='selinux' relabel='yes'/>
      </source>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </disk>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </controller>
    <controller type='usb' index='0'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:99:fe:f0'/>
      <source network='default'/>
      <target dev='vnet1'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/3'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/3'>
      <source path='/dev/pts/3'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <graphics type='spice' port='5901' autoport='yes' listen='127.0.0.1'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <sound model='ich6'>
      <alias name='sound0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </sound>
    <video>
      <model type='qxl' ram='65536' vram='65536' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </memballoon>
  </devices>
  <seclabel type='dynamic' model='selinux' relabel='yes'>
    <label>system_u:system_r:svirt_t:s0:c361,c495</label>
    <imagelabel>system_u:object_r:svirt_image_t:s0:c361,c495</imagelabel>
  </seclabel>
</domain>

2. Create 3 snapshots

# virsh snapshot-create-as qtest1

Domain snapshot 1393410436 created

#virsh snapshot-create-as qtest1

Domain snapshot 1393410489 created

#virsh snapshot-create-as qtest1

Domain snapshot 1393410593 created

3. Check the snapshot list

# virsh snapshot-list qtest1

1393410436

1393410489

1393410593

4. Do live commit

# virsh blockcommit qtest1 vda 1393410436 1393410593
error: invalid argument: top '(null)' in chain for 'vda' has no backing file

Comment 6 yangyang 2014-02-28 07:36:01 UTC
(In reply to yangyang from comment #4)
Updated the steps
> Reproduced on 
> kernel: 3.10.0-95.el7.x86_64
> libvirt-1.1.1-24.el7.x86_64
> 
> Steps:
>  1. Define and start a domain
> 
> # virsh dumpxml qtest1
> 
> <domain type='kvm' id='15'>
>   <name>qtest1</name>
>   <uuid>9b76e092-3941-4e36-abf9-ed6817b467dd</uuid>
>   <memory unit='KiB'>1048576</memory>
>   <currentMemory unit='KiB'>1048576</currentMemory>
>   <vcpu placement='static'>1</vcpu>
>   <resource>
>     <partition>/machine</partition>
>   </resource>
>   <os>
>     <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
>     <boot dev='hd'/>
>   </os>
>   <features>
>     <acpi/>
>     <apic/>
>     <pae/>
>   </features>
>   <clock offset='utc'/>
>   <on_poweroff>destroy</on_poweroff>
>   <on_reboot>restart</on_reboot>
>   <on_crash>restart</on_crash>
>   <devices>
>     <emulator>/usr/libexec/qemu-kvm</emulator>
>     <disk type='file' device='disk'>
>       <driver name='qemu' type='qcow2' cache='none'/>
>       <source file='/migration/qtest1.img'>
>         <seclabel model='selinux' relabel='yes'/>
>       </source>
>       <target dev='vda' bus='virtio'/>
>       <alias name='virtio-disk0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x06'
> function='0x0'/>
>     </disk>
>     <controller type='virtio-serial' index='0'>
>       <alias name='virtio-serial0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x05'
> function='0x0'/>
>     </controller>
>     <controller type='usb' index='0'>
>       <alias name='usb0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x01'
> function='0x2'/>
>     </controller>
>     <controller type='pci' index='0' model='pci-root'>
>       <alias name='pci.0'/>
>     </controller>
>     <interface type='network'>
>       <mac address='52:54:00:99:fe:f0'/>
>       <source network='default'/>
>       <target dev='vnet1'/>
>       <model type='virtio'/>
>       <alias name='net0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x03'
> function='0x0'/>
>     </interface>
>     <serial type='pty'>
>       <source path='/dev/pts/3'/>
>       <target port='0'/>
>       <alias name='serial0'/>
>     </serial>
>     <console type='pty' tty='/dev/pts/3'>
>       <source path='/dev/pts/3'/>
>       <target type='serial' port='0'/>
>       <alias name='serial0'/>
>     </console>
>     <channel type='spicevmc'>
>       <target type='virtio' name='com.redhat.spice.0'/>
>       <alias name='channel0'/>
>       <address type='virtio-serial' controller='0' bus='0' port='1'/>
>     </channel>
>     <input type='tablet' bus='usb'>
>       <alias name='input0'/>
>     </input>
>     <input type='mouse' bus='ps2'/>
>     <graphics type='spice' port='5901' autoport='yes' listen='127.0.0.1'>
>       <listen type='address' address='127.0.0.1'/>
>     </graphics>
>     <sound model='ich6'>
>       <alias name='sound0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x04'
> function='0x0'/>
>     </sound>
>     <video>
>       <model type='qxl' ram='65536' vram='65536' heads='1'/>
>       <alias name='video0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x02'
> function='0x0'/>
>     </video>
>     <memballoon model='virtio'>
>       <alias name='balloon0'/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x07'
> function='0x0'/>
>     </memballoon>
>   </devices>
>   <seclabel type='dynamic' model='selinux' relabel='yes'>
>     <label>system_u:system_r:svirt_t:s0:c361,c495</label>
>     <imagelabel>system_u:object_r:svirt_image_t:s0:c361,c495</imagelabel>
>   </seclabel>
> </domain>
> 
2. Create 3 external snapshots
# cat snapshot1.xml

<domainsnapshot>
<description>Snapshot of OS install and updates</description>
<disks>
<disk name='/migration/qtest1.img'>
<source file='/migaration/qtest1-1.img'/>
</disk>
</disks>
</domainsnapshot>

# virsh snapshot-create qtest1 --disk-only snapshot1.xml

# cat snapshot2.xml

<domainsnapshot>
<description>Snapshot of OS install and updates</description>
<disks>
<disk name='/migration/qtest1-1.img'>
<source file='/migaration/qtest1-2.img'/>
</disk>
</disks>
</domainsnapshot>

#virsh snapshot-create qtest1 --disk-only snapshot2.xml

#cat snapshot3.xml

<domainsnapshot>
<description>Snapshot of OS install and updates</description>
<disks>
<disk name='/migration/qtest1-2.img'>
<source file='/migaration/qtest1-3.img'/>
</disk>
</disks>
</domainsnapshot>

#virsh snapshot-create qtest1 --disk-only snapshot3.xml

3. # virsh blockcommit qtest1 --verbose --path vda --top /migration/qtest1-3.img --base /migration/qtest1-1.img --wait
Block Commit: [100 %] 

The job cannot be terminated when it finished.

Comment 9 Adam Litke 2014-05-21 14:48:51 UTC
Hi Eric,

In order for a management application to provide feedback to a user regarding which image files can be merged we will need a way to check whether virDomainBlockCommit supports an active layer merge (@top == active layer).  Do you have any thoughts on how this should be exposed via the libvirt API?

Comment 10 Eric Blake 2014-05-21 14:57:02 UTC
(In reply to Adam Litke from comment #9)
> Hi Eric,
> 
> In order for a management application to provide feedback to a user
> regarding which image files can be merged we will need a way to check
> whether virDomainBlockCommit supports an active layer merge (@top == active
> layer).  Do you have any thoughts on how this should be exposed via the
> libvirt API?

Oddly enough, I do!

https://www.redhat.com/archives/libvir-list/2014-May/msg00564.html

I'm in the middle of patches to blockcommit so that attempts to commit the active layer will fail unless you specify a new flag, and where the new flag fails if qemu is too old to support an active merge.  I'm on track to have the patches upstream for 1.2.5.

Comment 11 Eric Blake 2014-05-21 15:08:38 UTC
I will probably also export a capability marker for whether qemu supports live commits, similar to what was done here:

commit 85a3eb8a6d44e4501c00c9aeed0039ccaf29cdc5
Author: Francesco Romani <fromani@redhat.com>
Date:   Mon Mar 17 16:19:44 2014 +0100

    qemu: export disk snapshot support in capabilities
    
    This patch adds an element to QEMU's capability XML, to
    show if the underlying QEMU binary supports the live disk
    snapshotting or not.
    This allows any client to know ahead of time if the feature
    is available.
    
    Without this information available, the only way to check
    for the snapshot support is to request one and check for
    errors.
    
    Signed-off-by: Francesco Romani <fromani@redhat.com>

Comment 12 Adam Litke 2014-05-21 15:33:24 UTC
Thanks Eric.  This should work well for us.

Comment 13 Adam Litke 2014-05-22 15:03:19 UTC
Hi Eric,

Would you be willing to commit to having the capability marker you mentioned in comment 11?  If so, can we agree on the exact name so I can begin to check for it in vdsm?

Comment 14 Eric Blake 2014-06-23 23:33:55 UTC
Capability XML proposal at:
https://www.redhat.com/archives/libvir-list/2014-June/msg01097.html

Comment 15 Jiri Denemark 2014-07-30 14:49:16 UTC
Finished upstream by v1.2.7-rc1-21-gcfb16b8:

commit cfb16b8ed7bf5a082566e36b658945028cdffc59
Author: Eric Blake <eblake@redhat.com>
Date:   Wed Jun 18 17:16:27 2014 -0600

    blockcommit: turn on active commit
    
    With this in place, I can (finally!) now do:
    
    virsh blockcommit $dom vda --shallow --verbose --pivot
    
    and watch qemu shorten the backing chain by one, followed by
    libvirt automatically updating the dumpxml output, effectively
    undoing the work of virsh snapshot-commit --no-metadata --disk-only.
    Commit is SOOOO much faster than blockpull, when I'm still fairly
    close in time to when the temporary qcow2 wrapper file was created
    via a snapshot operation!
    
    * src/qemu/qemu_driver.c (qemuDomainBlockCommit): Implement live
    commit.
    
    Signed-off-by: Eric Blake <eblake@redhat.com>

commit 232a31bea3bfde7118bbb0c6594949b62b9bd2a0
Author: Eric Blake <eblake@redhat.com>
Date:   Mon Jul 28 21:46:44 2014 -0600

    blockcommit: track job type in xml
    
    A future patch is going to wire up qemu active block commit jobs;
    but as they have similar events and are canceled/pivoted in the
    same way as block copy jobs, it is easiest to track all bookkeeping
    for the commit job by reusing the <mirror> element.  This patch
    adds domain XML to track which job was responsible for creating a
    mirroring situation, and adds a job='copy' attribute to all
    existing uses of <mirror>.  Along the way, it also massages the
    qemu monitor backend to read the new field in order to generate
    the correct type of libvirt job (even though it requires a
    future patch to actually cause a qemu event that can be reported
    as an active commit).  It also prepares to update persistent XML
    to match changes made to live XML when a copy completes.
    
    * docs/schemas/domaincommon.rng: Enhance schema.
    * docs/formatdomain.html.in: Document it.
    * src/conf/domain_conf.h (_virDomainDiskDef): Add a field.
    * src/conf/domain_conf.c (virDomainBlockJobType): String conversion.
    (virDomainDiskDefParseXML): Parse job type.
    (virDomainDiskDefFormat): Output job type.
    * src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Distinguish
    active from regular commit.
    * src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set job type.
    (qemuDomainBlockPivot, qemuDomainBlockJobImpl): Clean up job type
    on completion.
    * tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml:
    Update tests.
    * tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml: Likewise.
    * tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml: New
    file.
    * tests/qemuxml2xmltest.c (mymain): Drive new test.
    
    Signed-off-by: Eric Blake <eblake@redhat.com>

Comment 17 Eric Blake 2014-08-06 20:18:04 UTC
Back to ASSIGNED - I found a pretty severe use-after-free bug that can crash libvirtd 1.2.7:
https://www.redhat.com/archives/libvir-list/2014-August/msg00214.html

Comment 18 Eric Blake 2014-08-07 19:23:59 UTC
Rebase to 1.2.8 will pick up:
commit 265680c58ebbee30bb70369e7d9905a599afbd6a
Author: Eric Blake <eblake@redhat.com>
Date:   Wed Aug 6 14:06:23 2014 -0600

    blockjob: fix use-after-free in blockcopy
    
    Commit febf84c2 tried to delay in-memory modification of the actual
    domain disk structure until after the qemu event was received.
    However, I missed that the code for block pivot had been temporarily
    setting disk->src = disk->mirror prior to the qemu command, in order
    to label the backing chain of a reused external blockcopy disk;
    and calls into qemu while still in that state before finally undoing
    things at the cleanup label.  Since the qemu event handler then does:
     virStorageSourceFree(disk->src);
     disk->src = disk->mirror;
    we have the sad race that a fast enough qemu event can cause a leak of
    the original disk->src, as well as a use-after-free of the disk->mirror
    contents, bad enough to crash libvirtd in some of my test runs, even
    though the common case of the qemu event being much later won't trip
    the race.
    
    I'll go wear the brown paper bag of shame, for introducing a crasher
    in between rc1 and rc2 of the freeze for 1.2.7 :(  My only
    consolation is that virDomainBlockJobAbort requires the domain:write
    ACL, so it is not a CVE.
    
    The valgrind report when the race occurs looks like:
    
    ==25612== Invalid read of size 4
    ==25612==    at 0x50E7C90: virStorageSourceGetActualType (virstoragefile.c:1948)
    ==25612==    by 0x209C0B18: qemuDomainDetermineDiskChain (qemu_domain.c:2473)
    ==25612==    by 0x209D7F6A: qemuProcessHandleBlockJob (qemu_process.c:1087)
    ==25612==    by 0x209F40C9: qemuMonitorEmitBlockJob (qemu_monitor.c:1357)
    ...
    ==25612==  Address 0xe4b5610 is 0 bytes inside a block of size 200 free'd
    ==25612==    at 0x4A07577: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==25612==    by 0x50839E9: virFree (viralloc.c:582)
    ==25612==    by 0x50E7E51: virStorageSourceFree (virstoragefile.c:2015)
    ==25612==    by 0x209D7EFF: qemuProcessHandleBlockJob (qemu_process.c:1073)
    ==25612==    by 0x209F40C9: qemuMonitorEmitBlockJob (qemu_monitor.c:1357)
    
    * src/qemu/qemu_driver.c (qemuDomainBlockPivot): Don't corrupt
    disk->src, and only label chain for blockcopy.
    
    Signed-off-by: Eric Blake <eblake@redhat.com>

Comment 19 Eric Blake 2014-08-14 04:15:11 UTC
Here's a thread detailing 28 patches needed to backport active commit for just files (no network support) to RHEL 7.0.z:

http://post-office.corp.redhat.com/archives/rhvirt-patches/2014-August/msg00372.html

Comment 28 Shanzhi Yu 2014-12-25 02:31:11 UTC
Verify this bug with libvirt-1.2.8-11.el7.x86_64

scenario I with disk type is "file"

1. Domain use raw format file as source

1.1 Define/start a domain 

# virsh dumpxml r7|grep disk -A 6
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.img'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

1.2 Create three external disk snapshot

# for i in 1 2 3;do virsh snapshot-create-as r7 s$i --disk-only --quiesce;done
Domain snapshot s1 created
Domain snapshot s2 created
Domain snapshot s3 created

# virsh dumpxml r7 |grep disk -A 16
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.s3'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-raw.s2'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7-raw.s1'/>
          <backingStore type='file' index='3'>
            <format type='raw'/>
            <source file='/var/lib/libvirt/images/r7-raw.img'/>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>

1.3 Do active blockcommit from top to middle
# virsh blockcommit r7 vda --active --base vda[1] --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7 |grep mirror -A 4 -B 16
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.s3'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-raw.s2'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7-raw.s1'/>
          <backingStore type='file' index='3'>
            <format type='raw'/>
            <source file='/var/lib/libvirt/images/r7-raw.img'/>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <mirror type='file' job='active-commit' ready='yes'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-raw.s2'/>
      </mirror>
# virsh blockjob r7 vda --pivot 

# virsh dumpxml r7 |grep disk -A 16
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-raw.s1'/>
        <backingStore type='file' index='2'>
          <format type='raw'/>
          <source file='/var/lib/libvirt/images/r7-raw.img'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>

1.4 Do active blockcommit from top to base
# virsh blockcommit r7 vda --active --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7 |grep mirror -A 4 -B 12
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-raw.s1'/>
        <backingStore type='file' index='2'>
          <format type='raw'/>
          <source file='/var/lib/libvirt/images/r7-raw.img'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <mirror type='file' job='active-commit' ready='yes'>
        <format type='raw'/>
        <source file='/var/lib/libvirt/images/r7-raw.img'/>
      </mirror>
      <target dev='vda' bus='virtio'/>
# virsh blockjob r7 vda --pivot 

# virsh dumpxml r7 |grep disk -A 4
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-raw.img'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

NB:
cmd "virsh blockcommit r7 vda --active --verbose --wait --pivot" will achieve same result with combination two cmd "virsh blockcommit r7 vda --active" without --pivot and "virsh blockjob r7 vda --pivot"

2. Domain use qcow2 format file as source

2.1 Define/start a domain 

# virsh dumpxml r7|grep disk -A 6
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

2.2 Create three external disk snapshot
# for i in 1 2 3;do virsh snapshot-create-as r7 s$i --disk-only --quiesce;done
Domain snapshot s1 created
Domain snapshot s2 created
Domain snapshot s3 created

2.3 Do active blockcommit from top to middle

# virsh blockcommit r7 vda --active --base vda[1] --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7 |grep mirror -A4 -B16
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-qcow2.s3'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-qcow2.s2'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7-qcow2.s1'/>
          <backingStore type='file' index='3'>
            <format type='qcow2'/>
            <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <mirror type='file' job='active-commit' ready='yes'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-qcow2.s2'/>
      </mirror>
      <target dev='vda' bus='virtio'/>
# virsh dumpxml r7|grep disk -A 12
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-qcow2.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-qcow2.s1'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>


2.4 Do active blockcommit from top to base
# virsh blockcommit r7 vda --active --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7 |grep mirror -A4 -B16
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-qcow2.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-qcow2.s1'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <mirror type='file' job='active-commit' ready='yes'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
      </mirror>
      <target dev='vda' bus='virtio'/>
# virsh blockjob r7 vda --pivot 

# virsh dumpxml r7|grep disk -A 12
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7-qcow2.img'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

scenario II with disk type is "block"

1. Domain use logical volume based on disk partition

1.1 Define/Start a domain 

# pvcreate /dev/sda7
  Physical volume "/dev/sda7" successfully created
# vgcreate VG01 /dev/sda7
  Volume group "VG01" successfully created
# lvcreate -L 10G -n LV01 VG01
  Logical volume "LV01" created.

# virsh dumpxml r7|grep disk -A 5
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source dev='/dev/VG01/LV01'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

1.2 Create three external disk snapshot
# for i in 1 2 3 ;do virsh snapshot-create-as r7 s$i --disk-only --diskspec vda,snapshot=external,file=/var/lib/libvirt/images/r7.s$i; done
Domain snapshot s1 created
Domain snapshot s2 created
Domain snapshot s3 created

# virsh dumpxml r7 |grep disk -A 16
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7.s3'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7.s2'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7.s1'/>
          <backingStore type='block' index='3'>
            <format type='raw'/>
            <source dev='/dev/VG01/LV01'/>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>

1.3 Do active blockcommit from top to middle
# virsh blockcommit r7 vda --active --base vda[1] --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase
# virsh dumpxml r7 |grep mirror -A4 -B16    
<disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7.s3'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7.s2'/>
        <backingStore type='file' index='2'>
          <format type='qcow2'/>
          <source file='/var/lib/libvirt/images/r7.s1'/>
          <backingStore type='block' index='3'>
            <format type='raw'/>
            <source dev='/dev/VG01/LV01'/>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <mirror type='file' job='active-commit' ready='yes'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7.s2'/>
      </mirror>

# virsh blockjob r7 vda --pivot 

# virsh dumpxml r7 |grep disk -A 12
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7.s1'/>
        <backingStore type='block' index='2'>
          <format type='raw'/>
          <source dev='/dev/VG01/LV01'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

1.4 Do active blockcommit from top to base
# virsh blockcommit r7 vda --active --verbose --wait
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7 |grep mirror -A4 -B16
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/libvirt/images/r7.s2'/>
      <backingStore type='file' index='1'>
        <format type='qcow2'/>
        <source file='/var/lib/libvirt/images/r7.s1'/>
        <backingStore type='block' index='2'>
          <format type='raw'/>
          <source dev='/dev/VG01/LV01'/>
          <backingStore/>
        </backingStore>
      </backingStore>
      <mirror type='block' job='active-commit' ready='yes'>
        <format type='raw'/>
        <source dev='/dev/VG01/LV01'/>
      </mirror>
..

# virsh blockjob r7 vda --pivot 


# virsh dumpxml r7 |grep disk -A 12
    <disk type='block' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source dev='/dev/VG01/LV01'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

scenario III with disk type is "network"

1. Domain use raw format file as source

1.1 Define/start a domain

# virsh dumpxml r7|grep disk -A 6
    <disk type='network' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

1.2 Create three external disk snapshot
# cat s1.xml 
<domainsnapshot>
<name>SNAP</name>
<disks>
<disk name='vda' type='network'>
<driver type='qcow2'/>
<source protocol='gluster' name='gluster-vol1/r7.SNAP'>
<host name='10.66.5.38'/>
</source>
</disk>
</disks>
</domainsnapshot>
# for i in s1 s2 s3;do sed -e s/SNAP/$i/g s1.xml >$i-snap.xml;virsh snapshot-create r7 $i-snap.xml --disk-only;done 
Domain snapshot s1 created from 's1-snap.xml'
Domain snapshot s2 created from 's2-snap.xml'
Domain snapshot s3 created from 's3-snap.xml'

# virsh dumpxml r7|grep disk -A24
    <disk type='network' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7.s3'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore type='network' index='1'>
        <format type='qcow2'/>
        <source protocol='gluster' name='gluster-vol1/r7.s2'>
          <host name='10.66.5.38'/>
        </source>
        <backingStore type='network' index='2'>
          <format type='qcow2'/>
          <source protocol='gluster' name='gluster-vol1/r7.s1'>
            <host name='10.66.5.38'/>
          </source>
          <backingStore type='network' index='3'>
            <format type='raw'/>
            <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
              <host name='10.66.5.38'/>
            </source>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>
..

1.3 Do active blockcommit from top to middle

#  virsh blockcommit r7 vda --active --base vda[1] --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

#  virsh dumpxml r7 |grep mirror -A4 -B24
    <disk type='network' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7.s3'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore type='network' index='1'>
        <format type='qcow2'/>
        <source protocol='gluster' name='gluster-vol1/r7.s2'>
          <host name='10.66.5.38'/>
        </source>
        <backingStore type='network' index='2'>
          <format type='qcow2'/>
          <source protocol='gluster' name='gluster-vol1/r7.s1'>
            <host name='10.66.5.38'/>
          </source>
          <backingStore type='network' index='3'>
            <format type='raw'/>
            <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
              <host name='10.66.5.38'/>
            </source>
            <backingStore/>
          </backingStore>
        </backingStore>
      </backingStore>
      <mirror type='network' job='active-commit' ready='yes'>
        <format type='qcow2'/>
        <source protocol='gluster' name='gluster-vol1/r7.s2'>
          <host name='10.66.5.38'/>
        </source>
      </mirror>
..
# virsh blockjob r7 vda --pivot 

# virsh dumpxml r7|grep disk -A24
    <disk type='network' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7.s2'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore type='network' index='1'>
        <format type='qcow2'/>
        <source protocol='gluster' name='gluster-vol1/r7.s1'>
          <host name='10.66.5.38'/>
        </source>
        <backingStore type='network' index='2'>
          <format type='raw'/>
          <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
            <host name='10.66.5.38'/>
          </source>
          <backingStore/>
        </backingStore>
      </backingStore>
      <target dev='vda' bus='virtio'/>

1.4 Do active blockcommit from top to base
# virsh blockcommit r7 vda --active --verbose --wait 
Block Commit: [100 %]
Now in synchronized phase

# virsh dumpxml r7|grep disk -A24
    <disk type='network' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7.s2'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore type='network' index='1'>
        <format type='qcow2'/>
        <source protocol='gluster' name='gluster-vol1/r7.s1'>
          <host name='10.66.5.38'/>
        </source>
        <backingStore type='network' index='2'>
          <format type='raw'/>
          <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
            <host name='10.66.5.38'/>
          </source>
          <backingStore/>
        </backingStore>
      </backingStore>
      <mirror type='network' job='active-commit' ready='yes'>
        <format type='raw'/>
        <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
          <host name='10.66.5.38'/>
        </source>
      </mirror>
      <target dev='vda' bus='virtio'/>

# virsh blockjob r7 vda --pivot 


# virsh dumpxml r7|grep disk -A6
    <disk type='network' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source protocol='gluster' name='gluster-vol1/r7-raw.img'>
        <host name='10.66.5.38'/>
      </source>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </disk>

So, blockcommit on active layer works fine. I will change this bug to VERIFIED status

Comment 29 Eric Blake 2015-01-14 19:40:49 UTC
*** Bug 1148201 has been marked as a duplicate of this bug. ***

Comment 31 errata-xmlrpc 2015-03-05 07:29:44 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://rhn.redhat.com/errata/RHSA-2015-0323.html


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