Skip to content

Commit def75b6

Browse files
committed
Merge remote-tracking branch 'origin/pr/835'
* origin/pr/835: storage/zfs: support shrinking volumes storage/lvm,file: support shrinking volumes Pull request description: Similar in purpose to #477, #478, #479 by @a-barinov in 2022, but with the shrinking check happening on the frontend side as [suggested](#477 (comment)) by @marmarek. The frontend already had such a check but only in the `qvm-volume` tool; QubesOS/qubes-core-admin-client#475 centralizes this check to `qubesadmin.storage.Volume.resize()` so that any other callers are protected as well. (Qube Manager's qube Settings dialog / `qubes-vm-settings` also has its own logic that avoids calling `resize()` if it would shrink.) Closes #479
2 parents ff099bd + cee4105 commit def75b6

4 files changed

Lines changed: 17 additions & 53 deletions

File tree

qubes/storage/file.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -362,14 +362,6 @@ def resize(self, size): # pylint: disable=invalid-overridden-method
362362
)
363363
raise qubes.exc.StoragePoolException(msg)
364364

365-
if size < self.size:
366-
raise qubes.exc.StoragePoolException(
367-
"For your own safety, shrinking of %s is"
368-
" disabled. If you really know what you"
369-
" are doing, use `truncate` on %s manually."
370-
% (self.name, self.vid)
371-
)
372-
373365
with open(self.path, "a+b") as fd:
374366
fd.truncate(size)
375367

qubes/storage/lvm.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -719,27 +719,19 @@ async def resize(self, size):
719719
msg = "Can not resize readonly volume {!s}".format(self)
720720
raise qubes.exc.StoragePoolException(msg)
721721

722-
if size < self.size:
723-
raise qubes.exc.StoragePoolException(
724-
"For your own safety, shrinking of %s is"
725-
" disabled (%d < %d). If you really know what you"
726-
" are doing, use `lvresize` on %s manually."
727-
% (self.name, size, self.size, self.vid)
728-
)
729-
730722
if size == self.size:
731723
return
732724

733725
if self.is_dirty() or self.snap_on_start:
734-
cmd = ["extend", self._vid_snap, str(size)]
726+
cmd = ["resize", self._vid_snap, str(size)]
735727
await qubes_lvm_coro(cmd, self.log)
736728
elif hasattr(self, "_vid_import") and os.path.exists(
737729
"/dev/" + self._vid_import
738730
):
739-
cmd = ["extend", self._vid_import, str(size)]
731+
cmd = ["resize", self._vid_import, str(size)]
740732
await qubes_lvm_coro(cmd, self.log)
741733
elif self.save_on_stop and not self.snap_on_start:
742-
cmd = ["extend", self._vid_current, str(size)]
734+
cmd = ["resize", self._vid_current, str(size)]
743735
await qubes_lvm_coro(cmd, self.log)
744736

745737
self._size = size
@@ -909,9 +901,9 @@ def _get_lvm_cmdline(cmd):
909901
"--",
910902
cmd[1],
911903
]
912-
elif action == "extend":
913-
assert len(cmd) == 3, "wrong number of arguments for extend"
914-
lvm_cmd = ["lvextend", "--size=" + cmd[2] + "B", "--", cmd[1]]
904+
elif action == "resize":
905+
assert len(cmd) == 3, "wrong number of arguments for resize"
906+
lvm_cmd = ["lvresize", "--size=" + cmd[2] + "B", "--", cmd[1]]
915907
elif action == "activate":
916908
assert len(cmd) == 2, "wrong number of arguments for activate"
917909
lvm_cmd = ["lvchange", "--activate=y", "--", cmd[1]]

qubes/storage/zfs.py

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,11 +1412,9 @@ async def resize_volume_async(
14121412
log: logging.Logger,
14131413
) -> None:
14141414
"""
1415-
Enlarge a volume to the specified size.
1415+
Resize a volume to the specified size.
14161416
14171417
The volume must exist.
1418-
1419-
An error will be raised if size is < current size.
14201418
"""
14211419
assert dataset_in_root(volume, self.root)
14221420
async with self._cache.locked():
@@ -2681,33 +2679,12 @@ def is_dirty(self) -> bool:
26812679
@qubes.storage.Volume.locked # type: ignore
26822680
async def resize(self, size: int) -> None:
26832681
"""
2684-
Expands volume.
2685-
2686-
Throws
2687-
:py:class:`qubst.storage.qubes.storage.StoragePoolException` if
2688-
given size is less than current_size.
2689-
"""
2690-
# FIXME: there does not seem to be a pathway to, but there
2691-
# should be a pathway to, reducing the storage size of a
2692-
# volume, whether it be by having to stop the VM first and
2693-
# then making a non-atomic clone / partial copy / rename
2694-
# of a zvol. It is annoying that ZFS prevents volumes from
2695-
# being reduced in size. It is further annoying that
2696-
# reduction of a volume requires the file system in it to
2697-
# be reduced first, which can only be done while the qube
2698-
# is running, but a Towers-of-Hanoi operation with datasets
2699-
# can only be performed with the qube off. Perhaps in the
2700-
# future we can have a qvm feature exposed that allows dom0
2701-
# to coordinate shrinking the file system and defers the
2702-
# Towers-of-Hanoi operation to after the qube has powered off.
2682+
Resizes volume.
2683+
"""
27032684
self.log.debug("Resizing %s to %s", self.volume, size)
27042685
mysize = self.size
27052686
if size == mysize:
27062687
return
2707-
if size < mysize:
2708-
raise qubes.exc.StoragePoolException(
2709-
"Shrinking of ZFS volume %s is not possible" % (self.volume,)
2710-
)
27112688
if await self.pool.accessor.volume_exists_async(
27122689
self.volume,
27132690
log=self.log,

qubes/tests/storage_zfs.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ def test_012_export_import(self) -> None:
418418
self.rc(volume.export_end(exported))
419419

420420
def test_013_resize_saveonstop(self) -> None:
421-
"""Test that a volume can be enlarged, but cannot be shrunk."""
421+
"""Test that a volume can be enlarged and shrunk."""
422422
volume = self.get_vol(ONEMEG_SAVE_ON_STOP)
423423
self.rc(volume.create())
424424

@@ -431,10 +431,13 @@ def test_013_resize_saveonstop(self) -> None:
431431
f"volume.size {volume.size} != newsize {newsize}",
432432
)
433433

434-
# Fail at shrinking.
435-
self.assertRaises(
436-
qubes.exc.StoragePoolException,
437-
lambda: self.rc(volume.resize(1024 * 1024)),
434+
# Shrink!
435+
newsize = 1 * 1024 * 1024
436+
self.rc(volume.resize(newsize))
437+
self.assertEqual(
438+
volume.size,
439+
newsize,
440+
f"volume.size {volume.size} != newsize {newsize}",
438441
)
439442

440443
def test_014_snaponstart_forgets_data(self) -> None:

0 commit comments

Comments
 (0)