diff --git a/diskimage_builder/block_device/level0/localloop.py b/diskimage_builder/block_device/level0/localloop.py index d5bd2c2e6..aaf8b5560 100644 --- a/diskimage_builder/block_device/level0/localloop.py +++ b/diskimage_builder/block_device/level0/localloop.py @@ -38,10 +38,16 @@ def image_delete(filename): os.remove(filename) -def loopdev_attach(filename): +def loopdev_attach(filename, block_size): + if str(block_size) not in ['512', '4096']: + logger.warning("Block device size is set to %s, only 512 and " + "4096 has been tested.", block_size) logger.info("loopdev attach") - logger.debug("Calling [sudo losetup --show -f %s]", filename) - block_device = exec_sudo(["losetup", "--show", "-f", filename]) + log_msg = ("Calling [sudo losetup --sector-size %s --show -f %s]" + % (str(block_size), filename)) + logger.debug(log_msg) + block_device = exec_sudo(["losetup", "--sector-size", str(block_size), + "--show", "-f", filename]) # [:-1]: Cut of the newline block_device = block_device[:-1] logger.info("New block device [%s]", block_device) @@ -85,6 +91,12 @@ class LocalLoopNode(NodeBase): self.image_dir = config['directory'] else: self.image_dir = default_config['image-dir'] + if 'DIB_BLOCK_SIZE' in os.environ: + self.block_size = os.environ['DIB_BLOCK_SIZE'] + elif 'block_size' in config: + self.block_size = config['block_size'] + else: + self.block_size = 512 self.filename = os.path.join(self.image_dir, self.name + ".raw") def get_edges(self): @@ -98,7 +110,7 @@ class LocalLoopNode(NodeBase): self.add_rollback(image_delete, self.filename) image_create(self.filename, self.size) - block_device = loopdev_attach(self.filename) + block_device = loopdev_attach(self.filename, self.block_size) self.add_rollback(loopdev_detach, block_device) if 'blockdev' not in self.state: diff --git a/diskimage_builder/block_device/level1/partitioning.py b/diskimage_builder/block_device/level1/partitioning.py index 31ef8e54c..d3ea2a637 100644 --- a/diskimage_builder/block_device/level1/partitioning.py +++ b/diskimage_builder/block_device/level1/partitioning.py @@ -95,6 +95,8 @@ class Partitioning(PluginBase): def _create_mbr(self): """Create partitions with MBR""" + # NOTE(TheJulia): This is funcitonally incompatible with block/sector + # sizing other than 512 bytes. with MBR(self.image_path, self.disk_size, self.align) as part_impl: for part_cfg in self.partitions: part_name = part_cfg.get_name() @@ -127,7 +129,10 @@ class Partitioning(PluginBase): def _create_gpt(self): """Create partitions with GPT""" - cmd = ['sgdisk', self.image_path] + # Use the loopback via device_path, as using the file means the + # partitioning is exposed to sector sizing of the OS, not of the + # underlying "device" provided by the loopback. + cmd = ['sgdisk', self.device_path] # This padding gives us a little room for rounding so we don't # go over the end of the disk diff --git a/diskimage_builder/block_device/tests/test_gpt.py b/diskimage_builder/block_device/tests/test_gpt.py index 5c4c80bee..cba3fe87b 100644 --- a/diskimage_builder/block_device/tests/test_gpt.py +++ b/diskimage_builder/block_device/tests/test_gpt.py @@ -63,7 +63,7 @@ class TestGPT(tc.TestGraphGeneration): node.create() # check the parted call looks right - parted_cmd = ['sgdisk', self.image_path, + parted_cmd = ['sgdisk', '/dev/loopX', '-n', '1:0:+8M', '-t', '1:EF00', '-c', '1:ESP', '-n', '2:0:+8M', '-t', '2:EF02', '-c', '2:BSP', '-n', '3:0:+1006M', '-t', '3:8300', '-c', '3:Root Part'] diff --git a/diskimage_builder/elements/block-device-efi-4k/README.rst b/diskimage_builder/elements/block-device-efi-4k/README.rst new file mode 100644 index 000000000..215d30735 --- /dev/null +++ b/diskimage_builder/elements/block-device-efi-4k/README.rst @@ -0,0 +1,19 @@ +================ +Block Device EFI +================ + +This provides a block-device configuration for the ``vm`` element to +get a single-partition disk suitable for EFI booting on a block device +which uses a native 4KiB sector size. This is important because GPT +partitioning relies on sector boundry placement and the GPT disk partition +table always starts on the second sector of the disk. + +Note on x86 this provides the extra `BIOS boot partition +<https://en.wikipedia.org/wiki/BIOS_boot_partition>`__ and a EFI boot +partition for maximum compatability. + +This element requires ``mkfs.vfat`` command to be available on the build +system, usually included in the dosfstools OS package. + +Furthermore, the sector size created by this element will not be compatible +with devices using 512 byte sectors. diff --git a/diskimage_builder/elements/block-device-efi-4k/block-device-default.yaml b/diskimage_builder/elements/block-device-efi-4k/block-device-default.yaml new file mode 100644 index 000000000..61fa67cfe --- /dev/null +++ b/diskimage_builder/elements/block-device-efi-4k/block-device-default.yaml @@ -0,0 +1,30 @@ +- local_loop: + name: image0 + block_size: 4096 +- partitioning: + base: image0 + label: gpt + partitions: + - name: ESP + type: 'EF00' + size: 500MiB + mkfs: + type: vfat + mount: + mount_point: /boot/efi + fstab: + options: "defaults" + fsck-passno: 2 + - name: BSP + type: 'EF02' + size: 8MiB + - name: root + type: '8300' + size: 100% + mkfs: + type: ext4 + mount: + mount_point: / + fstab: + options: "defaults" + fsck-passno: 1 diff --git a/diskimage_builder/elements/block-device-efi-4k/element-provides b/diskimage_builder/elements/block-device-efi-4k/element-provides new file mode 100644 index 000000000..c0180a2cb --- /dev/null +++ b/diskimage_builder/elements/block-device-efi-4k/element-provides @@ -0,0 +1 @@ +block-device \ No newline at end of file diff --git a/diskimage_builder/elements/block-device-efi-4k/environment.d/15-block-device.bash b/diskimage_builder/elements/block-device-efi-4k/environment.d/15-block-device.bash new file mode 100644 index 000000000..ad8a26745 --- /dev/null +++ b/diskimage_builder/elements/block-device-efi-4k/environment.d/15-block-device.bash @@ -0,0 +1,10 @@ +# +# Arch gate +# + +if [[ "ppc64 ppc64le ppc64el" =~ "$ARCH" ]]; then + echo "block-device-efi is not supported on Power; use block-device-gpt or block-device-mbr" + exit 1 +fi + +export DIB_BLOCK_DEVICE=efi diff --git a/doc/source/user_guide/building_an_image.rst b/doc/source/user_guide/building_an_image.rst index ac629e779..c7c3e8780 100644 --- a/doc/source/user_guide/building_an_image.rst +++ b/doc/source/user_guide/building_an_image.rst @@ -216,6 +216,22 @@ size directory (optional) The directory where the image is created. +block_size + (optional) Defaults to 512 bytes. Usable to set a different logical block + size, or in loopback context sector size, which will govern how partitioning + and filesystem utilities will interact with the device and ultimately the + block layout on disk. + Examples: 512, 4096. + This option is critical if you have block devices which natively operate + with 4KiB block sizes and need to craft an image to use boot from those + devices using a GPT partition table. This setting can also be asserted + using a DIB_BLOCK_SIZE environment variable which may be useful for + users who need to craft similar, but different block size images without + the need to separately maintain different block device YAML documents. + Please keep in mind, with larger block sizes, total disk image sizes + *and* partition sizes on the disk image will need to be perfectly + divisible by the block size being asserted. + Example: .. code-block:: yaml diff --git a/releasenotes/notes/add-4k-block-device-support-8397c2b6122d864c.yaml b/releasenotes/notes/add-4k-block-device-support-8397c2b6122d864c.yaml new file mode 100644 index 000000000..5c218a8d4 --- /dev/null +++ b/releasenotes/notes/add-4k-block-device-support-8397c2b6122d864c.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Adds the ability for diskimage-builder to create images with different + block sizes. By default, this remains at the default of 512 bytes, + but some newer devices require 4096 bytes to be used, which impacts + the overall layout rendering 512 byte images incompatible. This setting + can also be asserted and overridden using the ``DIB_BLOCK_SIZE`` + environment variable, but alternatively exists as a new ``block_size`` + parameter for ``local_loop`` section in block device YAML documents.