Skip to content

Commit ee8deea

Browse files
committed
Add coalesce with call to blktap
Signed-off-by: Damien Thenot <[email protected]>
1 parent 3a1184b commit ee8deea

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

drivers/qcow2util.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
import errno
55
import os
66
import re
7+
import time
78
import struct
89
import zlib
910
from pathlib import Path
1011

1112
import util
1213
import xs_errors
13-
from lvmcache import LVMCache
14+
from blktap2 import TapCtl
1415
from cowutil import CowUtil, CowImageInfo
16+
from lvmcache import LVMCache
1517

1618
MAX_QCOW_CHAIN_LENGTH: Final = 30
1719

@@ -421,7 +423,7 @@ def getBlockSize(self, path: str) -> int:
421423
return QCOW_CLUSTER_SIZE
422424

423425
@override
424-
def getFooterSize(self, path: str) -> int:
426+
def getFooterSize(self) -> int:
425427
return 0
426428

427429
@override
@@ -479,7 +481,7 @@ def getInfoFromLVM(
479481
) -> Optional[CowImageInfo]:
480482
lvcache = LVMCache(vgName)
481483
lvcache.refresh()
482-
if lvName not in self.lvs:
484+
if lvName not in lvcache.lvs:
483485
return None
484486
if not lvcache.is_active(lvName):
485487
lvcache.activateNoRefcount(lvName)
@@ -505,7 +507,6 @@ def getAllInfoFromVG(
505507
result: Dict[str, CowImageInfo] = dict()
506508
#TODO: handle parents, it needs to getinfo from parents also
507509
#TODO: handle exitOnError
508-
#TODO: If a vgName is given, is it already enabled? Do we need to enable LV on it too? It also only work for FileSR but LvmCowUtil uses it.
509510
if vgName:
510511
reg = re.compile(pattern)
511512
lvcache = LVMCache(vgName)
@@ -516,7 +517,6 @@ def getAllInfoFromVG(
516517
was_activated = False
517518
lvinfo = lvcache.lvs[lvName]
518519
if reg.match(lvName):
519-
util.SMlog("Match {}: {}".format(lvName, lvinfo))
520520
lvcache.refresh()
521521
if not lvcache.is_active(lvName):
522522
lvcache.activateNoRefcount(lvName)
@@ -529,8 +529,6 @@ def getAllInfoFromVG(
529529
lvcache.deactivateNoRefcount(lvName)
530530
except Exception as e:
531531
raise e
532-
else:
533-
util.SMlog("NOT {}: {}".format(lvName, lvinfo))
534532
return result
535533
else:
536534
pattern_p: Path = Path(pattern)
@@ -696,22 +694,37 @@ def getBlockBitmap(self, path: str) -> bytes:
696694

697695
@override
698696
def coalesce(self, path: str) -> int:
699-
pid_opener = util.get_openers_pid(path)
700-
if pid_opener is not None:
701-
raise xs_errors.XenError("LeafGCSkip", f"We can't coalesce the QCOW2 since it's in use. Openers: {pid_opener}")
702-
703-
allocated_blocks = self.getAllocatedSize(path)
704-
# -d on commit make it not empty the original image since we don't intend to keep it
705-
cmd = [QEMU_IMG, "commit", "-f", QCOW2_TYPE, path, "-d"]
706-
ret = cast(str, self._ioretry(cmd)) #TODO: parse for errors
707-
return allocated_blocks
697+
pid_openers = util.get_openers_pid(path)
698+
if pid_openers:
699+
if len(pid_openers) > 1:
700+
util.SMlog("Multiple openers for {}".format(path)) #TODO: There might be multiple PID?
701+
pid = pid_openers[0]
702+
l = TapCtl.list(pid=pid)
703+
if len(l) > 1: #TODO: There might more than one minor for this blktap?
704+
raise xs_errors.XenError("TapdiskAlreadyRunning", "There is multiple minor for this tapdisk process")
705+
minor = l[0]["minor"]
706+
TapCtl.commit(pid, minor, QCOW2_TYPE, path)
707+
#We need to wait for query to return finished
708+
#TODO: We are technically ininterruptible since being interrupted will only stop checking if the job is done
709+
status, nb, _ = TapCtl.query(pid, minor)
710+
if status == "undefined":
711+
return 0
712+
while status != "concluded":
713+
time.sleep(1)
714+
status, nb, _ = TapCtl.query(pid, minor)
715+
return nb
716+
else:
717+
allocated_blocks = self.getAllocatedSize(path)
718+
# -d on commit make it not empty the original image since we don't intend to keep it
719+
cmd = [QEMU_IMG, "commit", "-f", QCOW2_TYPE, path, "-d"]
720+
ret = cast(str, self._ioretry(cmd)) #TODO: parse for errors
721+
return allocated_blocks
708722

709723
@override
710724
def create(self, path: str, size: int, static: bool, msize: int = 0) -> None:
711725
cmd = [QEMU_IMG, "create", "-f", QCOW2_TYPE, path, str(size)]
712726
if static:
713727
cmd.extend(["-o", "preallocation=full"])
714-
#TODO: msize is ignored for now, it's used to preallocate metadata for VHD so it can use resize without journal
715728
self._ioretry(cmd)
716729
self.setHidden(path, False) #We add hidden header at creation
717730

@@ -727,7 +740,6 @@ def snapshot(
727740
parent_type = QCOW2_TYPE
728741
if parentRaw:
729742
parent_type = RAW_TYPE
730-
#TODO: msize is ignored for now, it's used to preallocate metadata for VHD so it can use resize without journal
731743
# TODO: checkEmpty? If it is False, then the parent could be empty and should still be used for snapshot
732744
cmd = [QEMU_IMG, "create", "-f", QCOW2_TYPE, "-b", parent, "-F", parent_type, path]
733745
self._ioretry(cmd)

0 commit comments

Comments
 (0)