commit: b4d9c5e7cb4bb3e1bee9e6105c90c9c0e3b0eb35
parent dc62d8242cafddb438e149fcd81e3272eea73da1
Author: Gábor Stefanik <netrolller.3d@gmail.com>
Date: Sun, 17 Dec 2023 21:59:00 +0100
Disk creation improvements
* Support specifying the size of the target disk image for qemu
* For bare metal, only pad the image to the next megabyte
* Use truncate() to extend images, instead of writing zeros (faster)
* Return None from get_disk() with nonexistent name
* Leave 1MiB on non-boot disks, or 1GiB on boot disks, unpartitioned
(for proper 4K alignment and to help preserve the srcfs or boot
partition creation)
* Fix qemu invocation when an external.img is not used
* Make -qr work with kernel bootstrap (will need kexec-fiwix fix)
Diffstat:
4 files changed, 61 insertions(+), 27 deletions(-)
diff --git a/lib/generator.py b/lib/generator.py
@@ -33,7 +33,7 @@ class Generator():
self.tmp_dir = tmpdir.path
self.external_dir = os.path.join(self.tmp_dir, 'external')
- def prepare(self, using_kernel=False, kernel_bootstrap=False):
+ def prepare(self, using_kernel=False, kernel_bootstrap=False, target_size=0):
"""
Prepare basic media of live-bootstrap.
/steps -- contains steps to be built
@@ -57,9 +57,14 @@ class Generator():
if self.repo_path or self.external_sources:
self.tmpdir.add_disk("external", filesystem="ext3")
self.tmpdir.mount_disk("external", "external")
+ else:
+ self.external_dir = os.path.join(self.tmp_dir, 'external')
elif using_kernel:
self.tmp_dir = os.path.join(self.tmp_dir, 'disk')
- self.tmpdir.add_disk("disk", filesystem="ext3")
+ self.tmpdir.add_disk("disk",
+ filesystem="ext3",
+ size=(target_size + "M") if target_size else "16G",
+ bootable=True)
self.tmpdir.mount_disk("disk", "disk")
self.external_dir = os.path.join(self.tmp_dir, 'external')
@@ -86,7 +91,7 @@ class Generator():
shutil.copytree(self.repo_path, repo_dir)
if kernel_bootstrap:
- self.create_builder_hex0_disk_image(os.path.join(self.tmp_dir, 'disk.img'))
+ self.create_builder_hex0_disk_image(os.path.join(self.tmp_dir, 'disk.img'), target_size)
if kernel_bootstrap and (self.external_sources or self.repo_path):
self.tmpdir.umount_disk('external')
@@ -149,7 +154,7 @@ class Generator():
def distfiles(self):
"""Copy in distfiles"""
def copy_no_network_distfiles(out):
- # Note that no network == no disk for kernel bootstrap mode
+ # Note that "no disk" implies "no network" for kernel bootstrap mode
pre_src_path = os.path.join(self.git_dir, 'steps', 'pre-network-sources')
with open(pre_src_path, 'r', encoding="utf-8") as source_list:
for file in source_list.readlines():
@@ -222,7 +227,7 @@ class Generator():
os.chdir(save_cwd)
- def create_builder_hex0_disk_image(self, image_file_name):
+ def create_builder_hex0_disk_image(self, image_file_name, size):
"""Create builder-hex0 disk image"""
shutil.copyfile(os.path.join('seed', 'stage0-posix', 'bootstrap-seeds',
'NATIVE', 'x86', 'builder-hex0-x86-stage1.img'),
@@ -250,11 +255,10 @@ class Generator():
image_file.write(b'\0' * round_up)
current_size += round_up
- # fill file with zeros up to desired size, one megabyte at a time
- with open(image_file_name, 'ab') as image_file:
- while current_size < 16384 * megabyte:
- image_file.write(b'\0' * megabyte)
- current_size += megabyte
+ # extend file up to desired size
+ if current_size < size * megabyte:
+ with open(image_file_name, 'ab') as image_file:
+ image_file.truncate(size * megabyte)
def check_file(self, file_name, expected_hash):
"""Check hash of downloaded source file."""
diff --git a/lib/tmpdir.py b/lib/tmpdir.py
@@ -60,10 +60,21 @@ class Tmpdir:
self._type = TmpType.TMPFS
# pylint: disable=too-many-arguments
- def add_disk(self, name, size="16G", filesystem="ext4", tabletype="msdos", mkfs_args=None):
+ def add_disk(self,
+ name,
+ size="16G",
+ filesystem="ext4",
+ tabletype="msdos",
+ bootable=False,
+ mkfs_args=None):
"""Add a disk"""
disk_path = os.path.join(self.path, f"{name}.img")
- self._disks[name] = create_disk(disk_path, tabletype, filesystem, size, mkfs_args=mkfs_args)
+ self._disks[name] = create_disk(disk_path,
+ tabletype,
+ filesystem,
+ size,
+ bootable,
+ mkfs_args)
self._disk_filesystems[name] = filesystem
# Allow executing user to access it
run_as_root("chown", getpass.getuser(), self._disks[name])
@@ -87,4 +98,4 @@ class Tmpdir:
def get_disk(self, name):
"""Get the path to a device of a disk"""
- return self._disks[name]
+ return self._disks.get(name)
diff --git a/lib/utils.py b/lib/utils.py
@@ -31,7 +31,8 @@ def run_as_root(*args, **kwargs):
return run("sudo", *args, **kwargs)
return run(*args, **kwargs)
-def create_disk(image, disk_type, fs_type, size, mkfs_args=None):
+# pylint: disable=too-many-arguments
+def create_disk(image, disk_type, fs_type, size, bootable=False, mkfs_args=None):
"""Create a disk image, with a filesystem on it"""
if mkfs_args is None:
mkfs_args = []
@@ -42,7 +43,7 @@ def create_disk(image, disk_type, fs_type, size, mkfs_args=None):
# Create the partition
if disk_type != "none":
run_as_root('parted', '--script', image, 'mklabel', disk_type, 'mkpart',
- 'primary', fs_type, '0%', '100%')
+ 'primary', fs_type, '1GiB' if bootable else '1MiB', '100%')
run_as_root('partprobe', loop_dev)
run_as_root('mkfs.' + fs_type, loop_dev + "p1", *mkfs_args)
return loop_dev
diff --git a/rootfs.py b/rootfs.py
@@ -39,7 +39,7 @@ def create_configuration_file(args):
if args.repo or args.external_sources:
config.write("DISK=sdb1\n")
else:
- config.write("DISK=sdb\n")
+ config.write("DISK=sda\n")
config.write("KERNEL_BOOTSTRAP=True\n")
else:
config.write("DISK=sda1\n")
@@ -98,6 +98,8 @@ def main():
default="qemu-system-x86_64")
parser.add_argument("-qr", "--qemu-ram", help="Memory (in megabytes) allocated to QEMU VM",
default=4096)
+ parser.add_argument("-qs", "--target-size", help="Size of the target image (for QEMU only)",
+ default="16G")
parser.add_argument("-qk", "--kernel", help="Custom sysa kernel to use")
parser.add_argument("-b", "--bare-metal", help="Build images for bare metal",
@@ -136,6 +138,15 @@ def main():
if int(args.cores) < 1:
raise ValueError("Must use one or more cores.")
+ # Target image size validation
+ if args.qemu:
+ if int(str(args.target_size).rstrip('gGmM')) < 1:
+ raise ValueError("Please specify a positive target size for qemu.")
+ args.target_size = (int(str(args.target_size).rstrip('gGmM')) *
+ (1024 if str(args.target_size).lower().endswith('g') else 1))
+ else:
+ args.target_size = 0
+
# bootstrap.cfg
try:
os.remove(os.path.join('sysa', 'bootstrap.cfg'))
@@ -158,9 +169,9 @@ def main():
repo_path=args.repo,
early_preseed=args.early_preseed)
- bootstrap(args, generator, tmpdir)
+ bootstrap(args, generator, tmpdir, args.target_size)
-def bootstrap(args, generator, tmpdir):
+def bootstrap(args, generator, tmpdir, size):
"""Kick off bootstrap process."""
print(f"Bootstrapping {args.arch} -- SysA")
if args.chroot:
@@ -224,18 +235,18 @@ print(shutil.which('chroot'))
elif args.bare_metal:
if args.kernel:
- generator.prepare(using_kernel=True)
+ generator.prepare(using_kernel=True, target_size=size)
print("Please:")
print(" 1. Take tmp/initramfs and your kernel, boot using this.")
print(" 2. Take tmp/disk.img and put this on a writable storage medium.")
else:
- generator.prepare(kernel_bootstrap=True)
+ generator.prepare(kernel_bootstrap=True, target_size=size)
print("Please:")
print(" 1. Take tmp/disk.img and write it to a boot drive and then boot it.")
else:
if args.kernel:
- generator.prepare(using_kernel=True)
+ generator.prepare(using_kernel=True, target_size=size)
run(args.qemu_cmd,
'-enable-kvm',
@@ -249,17 +260,24 @@ print(shutil.which('chroot'))
'-nographic',
'-append', 'console=ttyS0 root=/dev/sda1 rootfstype=ext3 init=/init rw')
else:
- generator.prepare(kernel_bootstrap=True)
- run(args.qemu_cmd,
+ generator.prepare(kernel_bootstrap=True, target_size=size)
+ arg_list = [
'-enable-kvm',
- '-m', "4G",
+ '-m', str(args.qemu_ram) + 'M',
'-smp', str(args.cores),
'-no-reboot',
- '-drive', 'file=' + os.path.join(generator.tmp_dir, 'disk.img') + ',format=raw',
- '-drive', 'file=' + tmpdir.get_disk("external") + ',format=raw',
+ '-drive', 'file=' + os.path.join(generator.tmp_dir, 'disk.img') + ',format=raw'
+ ]
+ if tmpdir.get_disk("external") is not None:
+ arg_list += [
+ '-drive', 'file=' + tmpdir.get_disk("external") + ',format=raw',
+ ]
+ arg_list += [
'-machine', 'kernel-irqchip=split',
'-nic', 'user,ipv6=off,model=e1000',
- '-nographic')
+ '-nographic'
+ ]
+ run(args.qemu_cmd, *arg_list)
if __name__ == "__main__":
main()