Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

volume: allow extend cow preallocated #380

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/vdsm/storage/blockVolume.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ def setParentTag(self, puuid):
def getMetaSlot(self):
return self._manifest.getMetaSlot()

def _extendSizeRaw(self, new_capacity):
def _extendSize(self, new_capacity):
# Since this method relies on lvm.extendLV (lvextend) when the
# requested size is equal or smaller than the current size, the
# request is siliently ignored.
Expand Down
2 changes: 1 addition & 1 deletion lib/vdsm/storage/fileVolume.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ def getLeaseVolumePath(self, vol_path=None):
# pylint: disable=no-member
return self._manifest.getLeaseVolumePath(vol_path)

def _extendSizeRaw(self, new_capacity):
def _extendSize(self, new_capacity):
volPath = self.getVolumePath()
cur_capacity = self.oop.os.stat(volPath).st_size

Expand Down
11 changes: 4 additions & 7 deletions lib/vdsm/storage/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,13 +1380,10 @@ def extendSize(self, new_capacity):
if self.isShared():
raise se.VolumeNonWritable(self.volUUID)

volFormat = self.getFormat()
if volFormat == sc.COW_FORMAT:
self.log.debug("skipping cow size extension for volume %s to "
if self.getType() == sc.SPARSE_VOL:
self.log.debug("skipping sparse size extension for volume %s to "
"capacity %s", self.volUUID, new_capacity)
return
elif volFormat != sc.RAW_FORMAT:
raise se.IncorrectFormat(self.volUUID)

# Note: This function previously prohibited extending non-leaf volumes.
# If a disk is enlarged a volume may become larger than its parent. In
Expand Down Expand Up @@ -1416,7 +1413,7 @@ def extendSize(self, new_capacity):
"Extend size for volume: " + self.volUUID, "volume",
"Volume", "extendSizeFinalize",
[self.sdUUID, self.imgUUID, self.volUUID]))
self._extendSizeRaw(new_capacity)
self._extendSize(new_capacity)

self.syncMetadata() # update the metadata

Expand Down Expand Up @@ -1594,7 +1591,7 @@ def newVolumeLease(cls, metaId, sdUUID, volUUID):
def getImageVolumes(cls, sdUUID, imgUUID):
return cls.manifestClass.getImageVolumes(sdUUID, imgUUID)

def _extendSizeRaw(self, newSize):
def _extendSize(self, newSize):
raise NotImplementedError

# Used only for block volume
Expand Down
81 changes: 81 additions & 0 deletions tests/storage/blocksd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,87 @@ def test_reduce_volume_skipped(domain_factory, fake_task, fake_sanlock):
assert dom.getVolumeSize(img_uuid, vol_id).apparentsize == vol_capacity


@requires_root
@pytest.mark.root
def test_extend_volume(domain_factory, fake_task, fake_sanlock):
"""
Test added to verify fix for https://bugzilla.redhat.com/2170689.
COW preallocated volumes should be extended when demanded. Otherwise,
VMs on preallocated disks will pause when reaching the volume truesize.

To avoid slowness of creating loop devices and storage domains for every
test, avoid parametrized test, just create as many volumes as needed
to test, and check them in one execution.
"""
vol_formats = [
sc.COW_FORMAT,
sc.RAW_FORMAT
]
sd_uuid = str(uuid.uuid4())
dom = domain_factory.create_domain(sd_uuid=sd_uuid, version=5)

img_uuid = str(uuid.uuid4())
vol_info = [(str(uuid.uuid4()), fmt) for fmt in vol_formats]
vol_capacity = 3 * GiB
new_capacity = 5 * GiB

for vol_uuid, vol_format in vol_info:
dom.createVolume(
imgUUID=img_uuid,
capacity=vol_capacity,
volFormat=vol_format,
preallocate=sc.PREALLOCATED_VOL,
diskType=sc.DATA_DISKTYPE,
volUUID=vol_uuid,
desc="Base volume",
srcImgUUID=sc.BLANK_UUID,
srcVolUUID=sc.BLANK_UUID)

# Produce and extend volume to the new capacity.
vol = dom.produceVolume(img_uuid, vol_uuid)
vol.extendSize(new_capacity)

# Check that volume size has changed.
vol_size = dom.getVolumeSize(img_uuid, vol_uuid)
assert vol_size.truesize == new_capacity
assert vol_size.apparentsize == new_capacity


@requires_root
@pytest.mark.root
def test_extend_volume_skipped(domain_factory, fake_task, fake_sanlock):
sd_uuid = str(uuid.uuid4())
dom = domain_factory.create_domain(sd_uuid=sd_uuid, version=5)

img_uuid = str(uuid.uuid4())
vol_id = str(uuid.uuid4())
vol_capacity = 10 * GiB
new_capacity = 15 * GiB

dom.createVolume(
imgUUID=img_uuid,
capacity=vol_capacity,
volFormat=sc.COW_FORMAT,
preallocate=sc.SPARSE_VOL,
diskType=sc.DATA_DISKTYPE,
volUUID=vol_id,
desc="Base volume",
srcImgUUID=sc.BLANK_UUID,
srcVolUUID=sc.BLANK_UUID)

# Obtain the volume size before the extend call.
initial_vol_size = dom.getVolumeSize(img_uuid, vol_id)

# Produce and extend volume to the new capacity, but we skip extends for
# cow sparse volumes.
vol = dom.produceVolume(img_uuid, vol_id)
vol.extendSize(new_capacity)

# Check that volume size has not changed.
vol_size = dom.getVolumeSize(img_uuid, vol_id)
assert vol_size == initial_vol_size


LVM_TAG_CHARS = string.ascii_letters + "0123456789_+.-/=!:#"

LVM_TAGS = [
Expand Down