self.metadata_mgr.refresh()
if self.state == SubvolumeStates.STATE_RETAINED:
return True
- else:
- raise VolumeException(-errno.EINVAL, "invalid state for subvolume '{0}' during create".format(self.subvolname))
+ return False
except MetadataMgrException as me:
if me.errno != -errno.ENOENT:
raise VolumeException(me.errno, "internal error while processing subvolume '{0}'".format(self.subvolname))
return False
@property
- def is_in_use(self):
- return not self.path == b''
+ def purgeable(self):
+ if not self.retained or self.list_snapshots() or self.has_pending_purges:
+ return False
+ return True
@property
def has_pending_purges(self):
except cephfs.Error as e:
if e.args[0] == errno.ENOENT:
try:
- log.debug("creating trash can: {0}".format(self.trash_dir))
self.fs.mkdir(self.trash_dir, 0o700)
except cephfs.Error as ce:
raise VolumeException(-ce.args[0], ce.args[1])
def _remove_on_failure(self, subvol_path, retained):
if retained:
log.info("cleaning up subvolume incarnation with path: {0}".format(subvol_path))
- self._trash_dir(subvol_path)
+ try:
+ self.fs.rmdir(subvol_path)
+ except cephfs.Error as e:
+ raise VolumeException(-e.args[0], e.args[1])
else:
log.info("cleaning up subvolume with path: {0}".format(self.subvolname))
self.remove()
self.uid = int(st.st_uid)
self.gid = int(st.st_gid)
self.mode = int(st.st_mode & ~stat.S_IFMT(st.st_mode))
- self.create_trashcan()
except MetadataMgrException as me:
if me.errno == -errno.ENOENT:
raise VolumeException(-errno.ENOENT, "subvolume '{0}' does not exist".format(self.subvolname))
def trash_incarnation_dir(self):
"""rename subvolume (uuid component) to trash"""
+ self.create_trashcan()
try:
bname = os.path.basename(self.path)
tpath = os.path.join(self.trash_dir, bname)
if self.list_snapshots():
if not retainsnaps:
raise VolumeException(-errno.ENOTEMPTY, "subvolume '{0}' has snapshots".format(self.subvolname))
+ else:
+ if not self.has_pending_purges:
+ self.trash_base_dir()
+ return
if self.state != SubvolumeStates.STATE_RETAINED:
self.trash_incarnation_dir()
self.metadata_mgr.update_global_section(MetadataManager.GLOBAL_META_KEY_PATH, "")
def remove_snapshot(self, snapname):
super(SubvolumeV2, self).remove_snapshot(snapname)
- if self.state == SubvolumeStates.STATE_RETAINED and not self.list_snapshots():
- # fake a trash entry for purge threads to find a job
- bname = str(uuid.uuid4()).encode('utf-8')
- self._link_dir(os.path.join(self.trash_dir, bname), bname)
+ if self.purgeable:
+ self.trash_base_dir()
# tickle the volume purge job to purge this entry, using ESTALE
raise VolumeException(-errno.ESTALE, "subvolume '{0}' has been removed as the last retained snapshot is removed".format(self.subvolname))
+ # if not purgeable, subvol is not retained, or has snapshots, or already has purge jobs that will garbage collect this subvol
with open_volume(volume_client, volname) as fs_handle:
with open_group(fs_handle, volume_client.volspec, groupname) as group:
with open_subvol(fs_handle, volume_client.volspec, group, subvolname, SubvolumeOpType.REMOVE) as subvolume:
- log.debug("subvolume.path={0}".format(subvolume.path))
- log.debug("subvolume.is_in_use={0}".format(subvolume.is_in_use))
- log.debug("subvolume.has_pending_purges={0}".format(subvolume.has_pending_purges))
- log.debug("subvolume.list_snapshots={0}".format(subvolume.list_snapshots()))
- if subvolume.is_in_use or subvolume.has_pending_purges or subvolume.list_snapshots():
- log.debug("not purging subvolume -- bailing out.")
+ log.debug("subvolume.path={0}, purgeable={1}".format(subvolume.path, subvolume.purgeable))
+ if not subvolume.purgeable:
return
# this is fine under the global lock -- there are just a handful
# of entries in the subvolume to purge. moreover, the purge needs
if stat.S_ISLNK(stx['mode']):
tgt = fs_handle.readlink(pth, 4096)
tgt = tgt[:stx['size']]
- log.debug("entry points to subvolume trash: {0}".format(tgt))
+ log.debug("purging entry pointing to subvolume trash: {0}".format(tgt))
delink = True
try:
- log.debug("purging subvolume trash: {0}".format(tgt))
trashcan.purge(tgt, should_cancel)
except VolumeException as ve:
if not ve.errno == -errno.ENOENT:
log.debug("purging trash link: {0}".format(purge_entry))
trashcan.delink(purge_entry)
else:
- log.debug("entry points to trash: {0}".format(pth))
- trashcan.purge(pth)
+ log.debug("purging entry pointing to trash: {0}".format(pth))
+ trashcan.purge(pth, should_cancel)
except cephfs.Error as e:
log.warn("failed to remove trash entry: {0}".format(e))
except VolumeException as ve: