2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-08-03 16:07:00 +00:00

Release the crypt device if encrypt_image is interrupted

Nothing unwound the loop device and dm-crypt mapping when the copy loop
raised, so interrupting a pack stranded both, still holding the profile's
rootimg.sfs.

Tear them down from a finally.  The retry loop moves with them, so also
honour its tries counter, as unpack_image already does; spinning forever
inside a finally would hang the interrupt it is meant to clean up after.

A bounded retry loop can also give up, and the detach that follows would
then fail with EBUSY and, raising from a finally, replace the exception
that brought us here.  Warn and leave both in place instead.
This commit is contained in:
Markus Hilger
2026-07-27 03:10:31 +02:00
parent 4e9052012f
commit 547ecf16d4
+30 -21
View File
@@ -385,28 +385,37 @@ def encrypt_image(plainfile, cryptfile, keyfile):
neededblocks += 1
loopdev = subprocess.check_output(['losetup', '-f']).decode('utf8').strip()
subprocess.check_call(['losetup', loopdev, cryptfile])
subprocess.check_call(['dmsetup', 'create', dmname, '--table', '0 {} crypt aes-xts-plain64 {} 0 {} 8'.format(neededblocks, key, loopdev)])
subprocess.check_call(['dmsetup', 'mknodes', dmname])
with open('/dev/mapper/{}'.format(dmname), 'wb') as cryptout:
with open(plainfile, 'rb+') as plainin:
lastoffset = 0
chunk = plainin.read(2097152)
while chunk:
fallocate(plainin.fileno(), FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, lastoffset, len(chunk))
lastoffset = plainin.tell()
cryptout.write(chunk)
try:
subprocess.check_call(['dmsetup', 'create', dmname, '--table', '0 {} crypt aes-xts-plain64 {} 0 {} 8'.format(neededblocks, key, loopdev)])
subprocess.check_call(['dmsetup', 'mknodes', dmname])
with open('/dev/mapper/{}'.format(dmname), 'wb') as cryptout:
with open(plainfile, 'rb+') as plainin:
lastoffset = 0
chunk = plainin.read(2097152)
mounted = True
tries = 30
time.sleep(0.1)
while mounted:
tries -= 1
try:
subprocess.check_call(['dmsetup', 'remove', dmname])
mounted = False
except subprocess.CalledProcessError:
time.sleep(0.1)
subprocess.check_call(['losetup', '-d', loopdev])
while chunk:
fallocate(plainin.fileno(), FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, lastoffset, len(chunk))
lastoffset = plainin.tell()
cryptout.write(chunk)
chunk = plainin.read(2097152)
finally:
mounted = True
tries = 30
time.sleep(0.1)
while mounted and tries:
tries -= 1
try:
subprocess.check_call(['dmsetup', 'remove', dmname])
mounted = False
except subprocess.CalledProcessError:
time.sleep(0.1)
if mounted:
sys.stderr.write(
'Warning: unable to remove {0}, it and {1} are left behind\n'.format(dmname, loopdev))
else:
try:
subprocess.check_call(['losetup', '-d', loopdev])
except subprocess.CalledProcessError:
sys.stderr.write('Warning: unable to detach {0}\n'.format(loopdev))
oum = os.umask(0o077)
with open(keyfile, 'w') as keyout:
keyout.write('aes-xts-plain64\n{}\n'.format(key))