Eduardo has uploaded a new change for review.

Change subject: BZ#836161 - Refactored deleteImage.
......................................................................

BZ#836161 - Refactored deleteImage.

Change-Id: I304ff5cd70186ffc9789cd1ac9337efa6c5ff695
Signed-off-by: Eduardo <[email protected]>
---
M vdsm/storage/blockSD.py
M vdsm/storage/fileSD.py
M vdsm/storage/hsm.py
M vdsm/storage/sd.py
4 files changed, 142 insertions(+), 14 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/06/8506/1

diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index e596fb6..d26e53c 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -163,13 +163,88 @@
         res[vName]['parent'] = vPar
         if vImg not in res[vName]['imgs']:
             res[vName]['imgs'].insert(0, vImg)
-        if vPar != sd.BLANK_UUID and \
-            not vName.startswith(blockVolume.image.REMOVED_IMAGE_PREFIX) \
+        if vPar != sd.BLANK_UUID \
+            and not vName.startswith(sd.REMOVED_IMAGE_PREFIX) \
+            and not vName.startswith(sd.ZERO_ME_IMAGE_PREFIX) \
             and vImg not in res[vPar]['imgs']:
             res[vPar]['imgs'].append(vImg)
 
     return dict((k, sd.ImgsPar(tuple(v['imgs']), v['parent']))
                     for k, v in res.iteritems())
+
+
+def deleteVolumes(sdUUID, vols):
+    lvm.removeLVs(sdUUID, vols)
+
+
+def _zeroVolume(sdUUID, volUUID):
+    """
+    This function requires an active LV.
+    """
+    # Change for zero 128 M chuncks and log.
+    # 128 M is the vdsm extent size default
+    cmd = tuple(constants.EXT_DD, "if=/dev/zero",
+                            "of=%s" % os.path.join("/dev", sdUUID, volUUID))
+    p = misc.execCmd(cmd, sudo=False, sync=False)
+    return p
+
+
+def _getZerosFinished(zeroPs):
+    for volUUID, zeroProc in zeroPs.items():
+        finished = {}
+        if not zeroProc.wait(0):
+            continue
+        else:
+            zeroPs.pop(volUUID)
+            finished[volUUID] = zeroProc.returncode
+            if zeroProc.returncode != 0:
+                log.warning("zeroing %s failed. %s", volUUID,
+                                                            zeroProc.stderr)
+            else:
+                log.debug("zeroing %s finished", volUUID)
+    return finished
+
+
+def zeroImgVolumes(sdUUID, imgUUID, volUUIDs):
+    # Put a sensible value for dd zeroing a 128 M or 1 G chunk and lvremove
+    # spent time.
+    ZERO_SLEEP = 60 # [seconds]
+    # Prepare for zeroing
+    try:
+        lvm.changelv(sdUUID, volUUIDs, (("-a", "y"), ("--deltag", imgUUID),
+                            ("--addtag", sd.ZERO_ME_IMAGE_PREFIX + imgUUID)))
+    except se.StorageException as e:
+        log.debug("SD %s, Image %s pre zeroing ops failed", sdUUID, imgUUID,
+                    volUUIDs)
+    try:
+        lvm.changelv(sdUUID, volUUIDs, ("--permission", "rw"))
+    except se.StorageException as e:
+        # Hope this only means that some volumes were already writable.
+        log.debug("IGNORED: %s", e)
+    # blank the volumes.
+    zeroPs = {}
+    for volUUID in volUUIDs:
+        zeroPs[volUUID] = _zeroVolume(sdUUID, volUUID)
+
+    # Yes, this is a potentially infinite loop. Kill the vdsm task.
+    last = time.time()
+    while len(zeroPs) > 0:
+        time.sleep(ZERO_SLEEP)
+        toDelete = []
+        for volUUID, rc in _getZerosFinished(zeroPs):
+            if rc != 0:
+                log.warning("zero leftover: %s/%s rc = %s", sdUUID, volUUID, 
rc)
+            else:
+                toDelete.append(volUUID)
+        if toDelete:
+            deleteVolumes(sdUUID, toDelete)
+
+        now = time.time()
+        if now - (last + 10 * ZERO_SLEEP) > 0:
+            log.warning("Still zeroing VG:%s LVs: %s",
+                                        sdUUID, zeroPs.iterkeys())
+
+    log.debug("All rm_zeroed VG:%s LVs: %s, img: %s", sdUUID, volUUIDs, 
imgUUID)
 
 
 class VGTagMetadataRW(object):
@@ -827,6 +902,12 @@
                         if i.startswith(blockVolume.TAG_PREFIX_IMAGE) ]
         return images
 
+    def deleteImage(self, sdUUID, imgUUID, volsImgs):
+        return deleteVolumes(sdUUID, volsImgs)
+
+    def zeroImage(self, sdUUID, imgUUID, volsImgs):
+        return zeroImgVolumes(sdUUID, imgUUID, volsImgs)
+
     def getAllVolumes(self):
         """
         Return all the images that depend on a volume.
diff --git a/vdsm/storage/fileSD.py b/vdsm/storage/fileSD.py
index 054fadb..d5b298f 100644
--- a/vdsm/storage/fileSD.py
+++ b/vdsm/storage/fileSD.py
@@ -62,6 +62,21 @@
     return True
 
 
+def getDomPath(sdUUID):
+    #  /rhev/data-center/mnt/export-path/sdUUID/dom_md/metadata
+    #  /rhev/data-center/mnt/blockSD/sdUUID/dom_md/metadata
+    pattern = os.path.join(sd.mountBasePath, '*', sdUUID)
+    # Warning! You need a global proc pool big as the number of NFS domains.
+    domPaths = getProcPool.glob.glob(pattern)
+    if len(domPaths) != 1:
+        raise se.StorageDomainLayoutError("domain", sdUUID)
+    return domPaths[0]
+
+
+def getImagePath(sdUUID, imgUUID):
+    return os.path.join(getDomPath(sdUUID), 'images', imgUUID)
+
+
 def getDomUuidFromMetafilePath(metafile):
     # Metafile path has pattern:
     #  /rhev/data-center/mnt/export-path/sdUUID/dom_md/metadata
@@ -298,6 +313,31 @@
                 imgList.append(os.path.basename(i))
         return imgList
 
+    def deleteImage(self, sdUUID, imgUUID, volsImgs):
+        oPath = getImagePath(sdUUID, imgUUID)
+        head, tail = self.oop.os.path.split(oPath)
+        nPath = os.tempnam(head, sd.REMOVED_IMAGE_PREFIX + tail)
+        try:
+            self.oop.os.rename(oPath, nPath)
+        except OSError as e:
+            self.log.error("image: %s can't be moved", oPath)
+            raise se.ImageDeleteError("%s %s" % (imgUUID, str(e)))
+        for volUUID in volsImgs:
+            volPath = os.path.join(nPath, volUUID)
+            try:
+                self.oop.os.remove(volPath)
+                self.oop.os.remove(volPath + '.meta')
+            except OSError as e:
+                self.log.error("vol: %s can't be removed.", volPath)
+        try:
+            self.oop.os.remove(nPath)
+        except OSError as e:
+            self.log.error("removed image dir: %s can't be removed", nPath)
+            raise se.ImageDeleteError("%s %s" % (imgUUID, str(e)))
+
+    def zeroImage(self, sdUUID, imgUUID, volsImgs):
+        return self.deleteImage(sdUUID, imgUUID, volsImgs)
+
     def getAllVolumes(self):
         """
         Return dict {volUUID: ((imgUUIDs,), parentUUID)} of the domain.
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 78eef77..2a8bc59 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -1260,24 +1260,26 @@
         Delete Image folder with all volumes
         """
         #vars.task.setDefaultException(se.ChangeMeError("%s" % args))
-        pool = self.getPool(spUUID) #Validates that the pool is connected. WHY?
-        self.validateSdUUID(sdUUID)
+        self.getPool(spUUID) #Validates that the pool is connected. WHY?
+        dom = self.validateSdUUID(sdUUID)
 
         vars.task.getExclusiveLock(STORAGE, imgUUID)
         vars.task.getSharedLock(STORAGE, sdUUID)
+        allVols = dom.getAllVolumes()
+        imgsByVol = sd.getVolsOfImage(allVols, imgUUID)
         # Do not validate if forced.
-        if not misc.parseBool(force):
-            pool.validateDelete(sdUUID, imgUUID)
-        # Rename image if postZero and perform delete as async operation
-        # else delete image in sync. stage
+        if not misc.parseBool(force) and not dom.isBackup() \
+                and not all(len(v.imgs) == 1 for v in imgsByVol.itervalues()):
+                msg = "Cannot delete shared image %s. volImgs: %s" \
+                                            % (imgUUID, imgsByVol)
+                raise se.CannotDeleteSharedVolume(msg)
+
+        # zeroImage will delete zeroed volumes at the end.
         if misc.parseBool(postZero):
-            newImgUUID = pool.preDeleteRename(sdUUID, imgUUID)
-            self._spmSchedule(spUUID, "deleteImage", pool.deleteImage, sdUUID, 
newImgUUID,
-                            misc.parseBool(postZero), misc.parseBool(force)
-            )
+            self._spmSchedule(spUUID, "zeroImage_%s" % imgUUID, dom.zeroImage,
+                              sdUUID, imgUUID, imgsByVol.keys())
         else:
-            pool.deleteImage(sdUUID, imgUUID,
-                              misc.parseBool(postZero), misc.parseBool(force))
+            dom.deleteImage(sdUUID, imgUUID, imgsByVol)
             # This is a hack to keep the interface consistent
             # We currently have race conditions in delete image, to quickly fix
             # this we delete images in the "synchronous" state. This only works
diff --git a/vdsm/storage/sd.py b/vdsm/storage/sd.py
index 55c5b12..fcb796c 100644
--- a/vdsm/storage/sd.py
+++ b/vdsm/storage/sd.py
@@ -134,12 +134,17 @@
 ImgsPar = namedtuple("ImgsPar", "imgs,parent")
 ISO_IMAGE_UUID = '11111111-1111-1111-1111-111111111111'
 BLANK_UUID = '00000000-0000-0000-0000-000000000000'
+REMOVED_IMAGE_PREFIX = "_remove_me_"
+ZERO_ME_IMAGE_PREFIX = "_zero_me_"
 
 # Blocks used for each lease (valid on all domain types)
 LEASE_BLOCKS = 2048
 
 UNICODE_MINIMAL_VERSION = 3
 
+storage_repository = config.get('irs', 'repository')
+mountBasePath = os.path.join(storage_repository, DOMAIN_MNT_POINT)
+
 
 def getVolsOfImage(allVols, imgUUID):
     """ Filter allVols dict for volumes related to imgUUID.


--
To view, visit http://gerrit.ovirt.org/8506
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I304ff5cd70186ffc9789cd1ac9337efa6c5ff695
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Eduardo <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to