diff --git a/image_creator/disk.py b/image_creator/disk.py index c3b5753e058b764b52da7138e1eaa15632cab6b2..2fc7a73d6d1a6448ed980cbc787c8c3a628faf5d 100644 --- a/image_creator/disk.py +++ b/image_creator/disk.py @@ -17,10 +17,8 @@ """Module hosting the Disk class.""" -from image_creator.util import get_command -from image_creator.util import try_fail_repeat -from image_creator.util import free_space -from image_creator.util import FatalError +from image_creator.util import get_command, try_fail_repeat, free_space, \ + FatalError, image_info from image_creator.bundle_volume import BundleVolume from image_creator.image import Image @@ -160,22 +158,43 @@ class Disk(object): mode = os.stat(self.file).st_mode device = self.file if stat.S_ISBLK(mode) else self._losetup(self.file) - size = blockdev('--getsz', device) + size = int(blockdev('--getsz', device)) + virtual_size = (image_info(device)['virtual-size'] + 511) // 512 + + # If the virtual_size is bigger than the block device size, we need to + # create a bigger block device padded with zeros, otherwise QEMU will + # freeze if it tries to enlarge the underlying file. + if virtual_size > size: + zeros = virtual_size - size + tablefd, table = tempfile.mkstemp() + try: + try: + os.write(tablefd, '0 %d linear %s 0\n' % (size, device)) + os.write(tablefd, '%d %d zero\n' % (size, zeros)) + finally: + os.close(tablefd) + padded = 'snf-image-creator-padded-%s' % uuid.uuid4().hex + dmsetup('create', padded, table) + self._add_cleanup(try_fail_repeat, dmsetup, 'remove', padded) + finally: + os.unlink(table) + device = "/dev/mapper/%s" % padded + size = virtual_size + self.out.output("Snapshotting media source ...", False) cowfd, cow = tempfile.mkstemp(dir=self.tmp) os.close(cowfd) self._add_cleanup(os.unlink, cow) # Create cow sparse file - dd('if=/dev/null', 'of=%s' % cow, 'bs=512', 'seek=%d' % int(size)) + dd('if=/dev/null', 'of=%s' % cow, 'bs=512', 'seek=%d' % size) cowdev = self._losetup(cow) - snapshot = uuid.uuid4().hex + snapshot = 'snf-image-creator-snapshot-%s' % uuid.uuid4().hex tablefd, table = tempfile.mkstemp() try: try: os.write(tablefd, - "0 %d snapshot %s %s n 8" % - (int(size), device, cowdev)) + "0 %d snapshot %s %s n 8\n" % (size, device, cowdev)) finally: os.close(tablefd) diff --git a/image_creator/util.py b/image_creator/util.py index d5370ffd06f9daa10e9a003719a680c1bdbeafda..abe280ffa970cb3236626f8ab0e99781c5839fad 100644 --- a/image_creator/util.py +++ b/image_creator/util.py @@ -24,6 +24,8 @@ import hashlib import time import os import re +import json +from sh import qemu_img class FatalError(Exception): @@ -31,6 +33,11 @@ class FatalError(Exception): pass +def image_info(image): + info = qemu_img('info', '--output', 'json', image) + return json.loads(str(info)) + + def get_command(command): """Return a file system binary command""" def find_sbin_command(command, exception):