Bug 1073305
| Summary: | resize volume can go beyond the pool capacity | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | yanbing du <ydu> |
| Component: | libvirt | Assignee: | John Ferlan <jferlan> |
| Status: | CLOSED ERRATA | QA Contact: | Virtualization Bugs <virt-bugs> |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | 7.0 | CC: | dyuan, jdenemar, jtomko, mzhan, rbalakri, yanyang, yisun, zhwang |
| Target Milestone: | rc | ||
| Target Release: | --- | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| Whiteboard: | |||
| Fixed In Version: | libvirt-1.2.16-1.el7 | Doc Type: | Bug Fix |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2015-11-19 05:45:01 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
|
Description
yanbing du
2014-03-06 07:37:57 UTC
ugh! Seems the resize is adjusting sizes of pool when it shouldn't necessarily be doing that. The way pools are set up and creation is handled, the "allocation" and "available" are adjusted based on the size of the allocation. Thus the following each results in the same output before and after: Before: $ virsh pool-info default Name: default UUID: 462942be-bd42-4b68-b315-e7fa3a4fdebc State: running Persistent: yes Autostart: no Capacity: 134.45 GiB Allocation: 62.04 GiB Available: 72.41 GiB $ virsh vol-create-as default bz1073305 10G 10G $ virsh vol-create-as default bz1073305 20G 10G $ virsh vol-create-as default bz1073305 100G 10G $ virsh pool-info default Name: default UUID: 462942be-bd42-4b68-b315-e7fa3a4fdebc State: running Persistent: yes Autostart: no Capacity: 134.45 GiB Allocation: 72.04 GiB Available: 62.41 GiB Theory being you are creating a sparse file and in order to adjust the size, the virsh vol-resize would be called with the --allocate value set (eg virsh vol-resize default 20G --allocate 20G). The "capacity" value is for the volume. Perhaps what "may" useful because of the confusion is for the pool to display whether the pool is "overcommitted" if every volume in the pool had it's allocation == capacity, but that's a different issue. Note we cannot change the "available" to be volume capacity based as that would change things in an unexpected manner perhaps for applications which use the available value to determine the size of what they "can" allocate in the pool. Anyway, unlike the 'Create' option, the 'Resize' option checks whether the incoming capacity value (not allocation value) would result in "enough space" in the pool for the capacity change: if (incoming capacity > existing capacity + pool available) fail So for my example, if I resize using 100G as my capacity and not allocation, things will fail because the following check passes: if (100 > 10 + 62) Now, if I successfully change my volume capacity and not allocation to 50G, then retry the same 100 I have: if (100 > 50 + 62) which allows the code to set the volume capacity to 100. NOTE: Prior to commit id '4f3287a41' (0.9.10), the check was "incoming capacity > existing allocation + available", which perhaps closer to what was necessary, but still not quite right. The issue being (following the Create logic) it doesn't matter what "capacity" changes to as long as the "allocation" (eg, what really takes space away) doesn't grow beyond the bounds of the pool. Whether being "overcommitted" with respect to the capacity of any volume(s) in the pool compared to the actual space available and "how" pool volumes perhaps may be allowed to grow past allocation to reach capacity without the libvirt pool logic realizing it (being notified) is a separate issue. That is, if I create a volume with a capacity of 20G and an allocation of 10G, if writes reach 10G, then since it's a sparse volume I still need to check if can we work our way to 20G without having libvirt do a resize that includes a larger allocation... I do think the fix to this "resize" issue involves an extra check regarding whether the incoming resize includes an allocation change or if it's just changing the allocation allowed value. It also requires a few more words in the vol-create-as and vol-resize virsh man page to describe the "interactions". Patch posted upstream: http://www.redhat.com/archives/libvir-list/2015-March/msg01477.html Patches reviewed and pushed:
git describe 1095230dee8e1bf184248b087695f45f867a4143
v1.2.14-81-g1095230
Lots of detail in the commit message:
commit 1095230dee8e1bf184248b087695f45f867a4143
Author: John Ferlan <jferlan>
Date: Fri Mar 27 09:48:59 2015 -0400
storage: Fix issues in storageVolResize
https://bugzilla.redhat.com/show_bug.cgi?id=1073305
When creating a volume in a pool, the creation allows the 'capacity'
value to be larger than the available space in the pool. As long as
the 'allocation' value will fit in the space, the volume will be created.
However, resizing the volume checks were made with the new absolute
capacity value against existing capacity + the available space without
regard for whether the new absolute capacity was actually allocating
space or not. For example, a pool with 75G of available space creates
a volume of 10G using a capacity of 100G and allocation of 10G will succeed;
however, if the allocation used a capacity of 10G instead and then tried
to resize the allocation to 100G the code would fail to allow the backend
to try the resize.
Furthermore, when updating the pool "available" and "allocation" values,
the resize code would just "blindly" adjust them regardless of whether
space was "allocated" or just "capacity" was being adjusted. This left
a scenario whereby a resize to 100G would fail; however, a resize to 50G
followed by one to 100G would both succeed. Again, neither was adjusting
the allocation value, just the "capacity" value.
This patch adds more logic to the resize code to understand whether the
new capacity value is actually "allocating" space as well and whether it
shrinking or expanding. Since unsigned arithmatic is involved, the possibility
that we adjust the pool size values incorrectly is probable.
This patch also ensures that updates to the pool values only occur if we
actually performed the allocation.
NB: The storageVolDelete, storageVolCreateXML, and storageVolCreateXMLFrom
each only updates the pool allocation/availability values by the target
volume allocation value.
The check in the above commit could be bypassed by using --shrink.
That should be fixed by:
commit 7211f66ad71066dc1bf9c428c70d8ba87ab791e9
Author: Ján Tomko <jtomko>
CommitDate: 2015-05-28 14:10:09 +0200
Simplify allocation check in storageVolResize
Since shrinking a volume below existing allocation is not allowed,
it is not possible for a successful resize with VOL_RESIZE_ALLOCATE
to increase the pool's available value.
Even with the SHRINK flag it is possible to extend the current
allocation or even the capacity. Remove the overflow when
computing delta with this flag and do the check even if the
flag was specified.
https://bugzilla.redhat.com/show_bug.cgi?id=1073305
git describe: v1.2.16-rc1-8-g7211f66
Verified:
ON libvirt-1.2.16-1.el7.x86_64
prepare a pool with around 8G capacity
# virsh pool-dumpxml pcap
<pool type='dir'>
<name>pcap</name>
<uuid>3a74d746-1551-4b5b-b8c1-a7ec7c5cd274</uuid>
<capacity unit='bytes'>8320901120</capacity>
<allocation unit='bytes'>37720064</allocation>
<available unit='bytes'>8283181056</available>
<source>
</source>
<target>
<path>/test</path>
<permissions>
<mode>0755</mode>
<owner>0</owner>
<group>0</group>
<label>system_u:object_r:unlabeled_t:s0</label>
</permissions>
</target>
</pool>
# virsh pool-info pcap
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: yes
Autostart: no
Capacity: 7.75 GiB
Allocation: 35.97 MiB
Available: 7.71 GiB
Scenario 1: only vol-resize capability, libvirt should allow the operation no matter how much capability-size provided. And pool's capability, allocation and available should not be changed.
1. # virsh vol-create-as pcap 1.img 1G 1G
Vol 1.img created
2. # virsh pool-refresh pcap; virsh pool-info pcap
Pool pcap refreshed
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: no
Autostart: no
Capacity: 7.75 GiB
Allocation: 1.04 GiB
Available: 6.71 GiB
3. # virsh vol-resize /test/1.img 100G
Size of volume '1.img' successfully changed to 100G
4. # virsh vol-info /test/1.img
Name: 1.img
Type: file
Capacity: 100.00 GiB
Allocation: 1.00 GiB
5. # virsh pool-refresh pcap; virsh pool-info pcap
Pool pcap refreshed
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: no
Autostart: no
Capacity: 7.75 GiB
Allocation: 1.04 GiB
Available: 6.71 GiB
<================================ pool info not modified as expect.
Scenario 2: vol-resize capability with --allocate, libvirt should allow the operation only if vol's newly allocated size is smaller than pool's available size.
1. clear the pool and prepare a vol again
# virsh vol-create-as pcap 1.img 1G 1G
Vol 1.img created
2. # virsh pool-info pcap
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: no
Autostart: no
Capacity: 7.75 GiB
Allocation: 1.04 GiB
Available: 6.71 GiB
3. # virsh vol-resize /test/1.img 8G --allocate
error: Failed to change size of volume '1.img' to 8G
error: operation failed: Not enough space left in storage pool <==== failed as expect. since allocation exceeds pool's available space.
4. # virsh vol-resize /test/1.img 7G --allocate
Size of volume '1.img' successfully changed to 7G <==== successfully when left space is enough
5. # virsh pool-info pcap
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: yes
Autostart: no
Capacity: 7.75 GiB
Allocation: 7.04 GiB
Available: 731.46 MiB
Scenario3: test with --shrink but try to extend capacity and allocation
clear the env and create a 1G volume
1. # virsh vol-create-as pcap 1.img 1G 1G
Vol 1.img created
2. # virsh pool-info pcap
Name: pcap
UUID: 3a74d746-1551-4b5b-b8c1-a7ec7c5cd274
State: running
Persistent: yes
Autostart: no
Capacity: 7.75 GiB
Allocation: 1.04 GiB
Available: 6.71 GiB
3. # virsh vol-resize --allocate --shrink /test/1.img 8G
error: Failed to change size of volume '1.img' to 8G
error: operation failed: Not enough space left in storage pool <====== expected
4. # virsh vol-resize --shrink /test/1.img 18G
Size of volume '1.img' successfully changed to 18G <==== expected
5. # virsh vol-info /test/1.img
Name: 1.img
Type: file
Capacity: 18.00 GiB <=== not limited, as expect
Allocation: 1.00 GiB
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/RHBA-2015-2202.html |