Skip to content

Generic Partitioning

Welma offers a mechanism to simplify storage space partitioning by using input files that contain all the necessary information to generate the final image.

Features:

  • Split the main Linux filesystem into smaller fs stored on distinct physical partitions, that can be updated separately.
  • Select which filesystem shall be verified by secure boot.
  • Select mounting options (read-only, read-write, noexec, ...).
  • Select software update mechanism for each partition: A/B, single, none.

To achieve this, Welma relies on two files: .part file and .split file:

Generic Partitioning Diagram

Part file

The .part file defines the physical layout of partitions on the storage device. Each entry specifies an individual partition on the disk.

Each entry is described on a separate line. Fields on each line are separated by tabs or spaces. Characters after '#' are comments and ignored. Blank lines are ignored. ${VAR} patterns are expanded from the same bitbake variables.

Each entry is made of 3 fields: "part" PARTNAME OPTIONS

Example:

meta-welma/split/welma.part
part    bootloader  update=single,dev=/dev/mmcblk0p1
part    boot        update=ab,dev=/dev/mmcblk0p3:/dev/mmcblk0p4
part    sysro       size=350M,update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6
part    appro       size=15M,version=0.0,update=ab,dev=/dev/mmcblk0p7:/dev/mmcblk0p8
part    sysrw       size=400M,dev=/dev/mmcblk0p9

Warning

The boot partition, which holds the Linux kernel (either in a FIT image or a comboapp) must always be positioned as the first A/B partition on the disk.

Partition Name (PARTNAME)

  • Must be unique in the file (several partitions cannot share the same name).
  • Must only use 7-bit ASCII lower-case letters, digits and dashes

Partition options (OPTIONS)

The OPTIONS field contains one or more OPTION sub-fields separated by comma (,). The OPTION dev= is mandatory. The others are optional.

OPTION can be:

  • dev=DEVICE or dev=DEVICE1:DEVICE2: Specifies the physical partition(s) on the disk where the filesystem should be installed. For A/B mode, 2 devices must be specified, separated by a colon (:). Eg: dev=/dev/mmcblk0p1 or dev=/dev/mmcblk0p4:/dev/mmcblk0p5.

    • You may use helper variables DEV_PART{A..Z}: if not previously defined, these are automatically defined from the following machine variables: BOOT_DEV_PATH, BOOT_DEV_PART_PREFIX and FIRST_ACTIVE_PARTITION_INDEX. Eg: if BOOT_DEV_PATH="/dev/mmcblk0", BOOT_DEV_PART_PREFIX="p", FIRST_ACTIVE_PARTITION_INDEX="3", then: DEV_PARTA="/dev/mmcblk0p3", DEV_PARTB="/dev/mmcblk0p4", and so on.
  • devoffset=VALUE: Specifies at which offset the partition starts, within the device (given by dev=). Default: 0.

    • Supported units: K (this is the default), M, G.
    • Not compatible with update= other than single.
    • Not compatible with devtype=flash.
  • devtype=VALUE: Specifies the type of the physical partition. This impacts how software update will write to the physical partition.

    • Supported values: block (block device, this is the default), flash (raw flash device, generally with dev=/dev/mtd...).
    • Not compatible with update= other than single.
  • size=VALUE: Specifies the size of the physical partition. Supported units for VALUE are K (kibibytes, KiB), M (MiB), and G (GiB), with the default unit being K. It generates a helper variable named PARTITION_SIZE_<partname>, which holds the corresponding size value for that partition.

    • If size is given together with update=single, it is used to limit the partition size, so that software update cannot write beyond.
    • Not compatible with devtype=flash.
  • update=VALUE: Specifies the software update mode for this partition. Supported values:

    • no: The partition is not subject to software update (this is the default).
    • ab: The partition may be updated in A/B mode and defines 2 physical partitions.
    • single: The partition may be updated in single mode.
  • version=VALUE: Specifies a version string. DISTRO_VERSION is the default value. This information used for:

    • creating files /etc/module.version inside each sub-filesystem
    • setting the version number in Mender artifacts (when using Mender)

Split file

The .split file defines how the root file system should have directories:

  • split in smaller file systems, with a split entry
  • stored on another file system, with a migrate entry.

This enables precise tailoring regarding:

  • mounting file systems read-only or read-write
  • updating file systems separately

Each entry is described on a separate line. Fields on each line are separated by tabs or spaces. Characters after '#' are comments and ignored. Blank lines are ignored. ${VAR} patterns are expanded from the same bitbake variables.

Example:

meta-welma/split/welma.split
split   boot    /boot   vfat    overhead=1.1,minsize=4096,boot,mount=ro
split   sysro   /       ext4    overhead=1.1,verity
split   appro   /app    ext4    overhead=1.1,extrasize=4096,verity,systemd
split   sysrw   /var    ext4    overhead=1.3,extrasize=390000,mount=defaults:noexec

migrate /home   /var/home   bind

Split entries

Each line that starts with the keyword split defines a new partition. This keyword is followed by the partition's name, the mount point, the file system type and filesystem options.

Filesystem Name

The filesystem name must comply with the following two rules:

  • It must be unique in the file (several filesystems cannot share the same name).
  • Only use lower-case characters, digits and dashes are supported
  • It must be defined in the part file

The mount point

The filesystem mount point must exist within the rootfs produced by the build. It serves as the source directory from which the file tree is taken to construct the final file system.

The Filesystem type

The type of file system selected must be supported by Yocto.

Options

The filesystem options supported in .split files are:

  • overhead (optional): It is a floating-point value representing the additional space required for filesystem metadata. It must always be greater than or equal to 1.0. Default value is set to 1.3.
  • minsize (optional): It specifies the minimum amount of space, in kilobytes, that must be allocated within the filesystem to ensure it can accommodate the necessary data and structure during creation. Default value is set to 8192.
  • extrasize (optional): It specifies the additional space, in kilobytes, that should be included in the filesystem beyond the total size of the files it contains. Default value is set to 0.
  • verity (optional): Flag indicating that the filesystem should be mounted with dm-verity. WELMA_SECURE_BOOT should be activated to be able to use verity option. Please refer to this page for more details about verity usge in Welma.
  • boot: Flag to be set for the filesystem that contains the Linux kernel (i.e fitimage, comboapp)
  • mount (optional): Specify the filesystem mount options, column separated. Default value is set to ro.
  • systemd (optional): Flag indicating that the filesystem's mount point should be included in the SYSTEMD_UNIT_PATH systemd user unit search path, allowing systemd services to be located and run from within this filesystem.

Migration entries

A migrate entry defines the process of relocating content of a directory to another place (either in the same partition, or a different one). In split files, Welma supports two migration methods: bind and link.

  • bind method is used to have the directory bind-mounted. For example:

    migrate   /home   /var/home   bind
    
    This line relocates the contents of /home to /var/home, and adds the following entry to /etc/fstab:
    /var/home       /home   none    defaults,bind   0       0
    

  • link method enables the conversion of a directory into a symbolic link by moving its contents to the target directory and then creating a symbolic link that points to this new location. For example:

    migrate /data/shared-data   /var/shared-data    link
    
    This line transfers the contents of /data/shared-data to /var/shared-data and then creates the following symbolic link:
    /data/shared-data -> /var/shared-data
    

Working with wic images

The .part and .split files do not produce a partitioned disk image. If you're using a tool such as wic to generate the final image, make sure to have its description file (wks) synchronized with the partition layout defined in the .part and .split files.

In the WKS description, you may use the following variables, that are set after the .part and .split files:

  • PARTITION_SIZE_<partname>: will be set to the value of the partition OPTION size=.
  • IMG_SUFFIX_<partname>: will be set to .verity if dm-verity is used.

Eg:

part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.sysro.ext4${IMG_SUFFIX_sysro}" --fixed-size ${PARTITION_SIZE_sysro}

Customize your partitioning scheme

Create your first minimal .part file

In this example, we explain how to create your first and minimal .part and .split files.

Preliminary assumptions:

  • You are using a layer meta-project for your specific project and your main image is meta-project/recipes-project/images/project-image.bb
  • You are using swupdate as SW update mechanism.
  • You are using Wic to produce a full sdcard image, and your wks file looks like:
meta-project/wic/project.wks.in
part --fixed-size 3M --source rawcopy --sourceparams="file=bootloader.bin"
part --fixed-size 50M --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.boot.vfat"
part --fixed-size 50M
part --fixed-size 400M --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.sysro.ext4"
part --fixed-size 400M
part --fixed-size 500M --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.sysrw.ext4"
bootloader --ptable gpt
  • Your target device has emmc storage (/dev/mmcblk0).

Procedure:

  • Create your .part file that will override Welma's:
    meta-project/split/welma.part
    part boot   update=ab,dev=/dev/mmcblk0p2:/dev/mmcblk0p3
    part sysro  update=ab,dev=/dev/mmcblk0p4:/dev/mmcblk0p5
    part sysrw  dev=/dev/mmcblk0p6
    
  • Create your .split file that will override Welma's:
    split   boot    /boot   vfat    mount=ro
    split   sysro   /       ext4    mount=ro
    split   sysrw   /var    ext4    extrasize=390000,mount=defaults:noexec
    

As a result:

  • bitbake project-image will generate SW update modules:
    ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.boot.swu
    ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.sysro.swu
    
  • You can send and install these onto your target (using updatectl install).

If you need to update the bootloader in single mode, please see the next section.

Upgrade from Welma 1.3.0

When upgrading from Welma 1.3.0 (or a prior version), you need to replace your partitions .conf file by a .part.

Example:

meta-project/files/partitions-project.conf
# NAME   MOUNTPOINT   DEVICE A         DEVICE B        OPTIONS
boot     /boot        /dev/mmcblk2p1   /dev/mmcblk2p2  boot
sysro    /            /dev/mmcblk2p3   /dev/mmcblk2p4
appro    /app         /dev/mmcblk2p5   /dev/mmcblk2p6
var      /var         /dev/mmcblk2p7

Should be replaced by:

meta-project/split/welma.part
part boot   update=ab,dev=/dev/mmcblk2p1:/dev/mmcblk2p2
part sysro  update=ab,dev=/dev/mmcblk2p3:/dev/mmcblk2p4
part appro  update=ab,dev=/dev/mmcblk2p5:/dev/mmcblk2p6
part var    dev=/dev/mmcblk0p7

And the boot option should be placed in the .split file:

meta-project/split/welma.split
...
split   boot    /boot   vfat    mount=ro,boot
...

Configure the bootloader with single mode update

In this example, we explain how to configure the bootloader partition. This will allow you to perform remote updates of the bootloader.

You can also use this example for other types of contents that will need to be updated, such as firmware images,...

Preliminary assumptions:

  • You are using a layer meta-project for all that is specific to your project.
  • You are using this .part file that is overriding Welma's default:
    meta-project/split/welma.part
    part    boot        update=ab,dev=/dev/mmcblk0p3:/dev/mmcblk0p4
    part    sysro       update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6
    part    appro       update=ab,dev=/dev/mmcblk0p7:/dev/mmcblk0p8
    part    sysrw       dev=/dev/mmcblk0p9
    
  • You are using swupdate as SW update mechanism.
  • The bootloader is a single binary
    • generated by Yocto in ${DEPLOY_DIR_IMAGE}/bootloader.bin
    • installed on your device on the emmc user partition (/dev/mmcblk0) at offset 32 KiB.

Procedure:

  • Add this line to meta-project/split/welma.part:
    part    bootloader  update=single,dev=/dev/mmcblk0,devoffset=32K
    
  • Specify the binary file of the bootloader that should be shipped for remote software update:
    meta-project/recipes-project/images/project-image.bb
    WELMA_UPDATE_MODULES[bootloader-src] = "${DEPLOY_DIR_IMAGE}/bootloader.bin"
    

As a result:

  • bitbake project-image will generate a SW update module for the bootloader: ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.bootloader.swu.
  • You can send and install this file onto your target (using updatectl install).

Mount rootfs in read-write mode

Though this is not recommended for production usage, at early stages of the developement cycle, it may be useful for developers to work with a read-write root filesystem.

This can be achieved as follows:

  • in the .split file:
    • remove the verity flag (if any)
    • add mount=rw

Eg:

meta-project/split/welma.split
...
split   sysro   /       ext4    overhead=1.1,mount=rw
...

  • if your /etc/fstab specifies read-only mode for /, then it overrides the previous and you also need to modify /etc/fstab and set read-write mode there.

Insert a data partition

In this example, we explain how to add a raw partition.

Preliminary assumptions:

  • Your partition layout is:

    | bootloader       |
    ... empty space  ...
    | kernel A         |
    | kernel B         |
    | sysro A          |
    | sysro B          |
    | sysrw            |
    

  • You are using a .part file like this one:

    part kernel  update=ab,dev=/dev/mmcblk0p2:/dev/mmcblk0p3
    part sysro   update=ab,dev=/dev/mmcblk0p4:/dev/mmcblk0p5
    part sysrw   dev=/dev/mmcblk0p6
    

  • You want to add a new partition in the empty space.

Procedure:

  • Modify your .part file to move the partition indexes by one:

    part boot   update=ab,dev=/dev/mmcblk0p3:/dev/mmcblk0p4
    part sysro  update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6
    part sysrw  dev=/dev/mmcblk0p7
    

  • If using U-Boot (or any other bootloader), make it aware that the partition index of the kernel was moved by one. We do that through the CONFIG_BOOTFLAGS_FIRST_ACTIVE_PARTITION parameter in our BSP adaptation layers.

  • Align your first-install procedure as well (for instance, if using wic then align your wks, etc.)

Full example

In this example we will configure our partitions as follows:

  • boot: 50Mb partition holding boot artifacts from /boot, with A/B update support to be mounted on /boot in read-only mode.
  • sys: 350Mb partition holding the Root filesystem, with A/B update and dm-verity support, mounted on /.
  • app: 50Mb partition hosting the application filesystem, with A/B update and systemd user units support, mounted on /app with dm-verity protection.

    Note

    The application Yocto recipes—including those that install systemd units— should install all their artifacts under the /app directory.

  • log: 500Mb partition holding the system logs, mounted on /var/log in read-write, noexec mode.

  • var: 400Mb partition holding the var filesystem, mounted on /var in read-write, noexec mode.

  • /home to be binded to /var/home

In this example, we’ll assume the platform has an eMMC enumerated at /dev/mmcblk0. The first partition will be used for the First Stage Bootloader and the second partition to store the Bootflags structure.

To implement this partitioning layout, follow these steps:

  • Add your meta-project to the build environment. Please refer to this page for more details

    Warning

    Please ensure that your project layers are listed first before meta-welma layer to be able to use your customized split and part files

  • Set BOOT_DEV_PATH, FIRST_ACTIVE_PARTITION_INDEX and BOOT_DEV_PART_PREFIX variables in your machine conf file:

    Machine configuration file
    BOOT_DEV_PART_PREFIX = "p"
    FIRST_ACTIVE_PARTITION_INDEX = "3"
    BOOT_DEV_PATH = "/dev/mmcblk0"
    

  • If U-Boot is used, make sure to set CONFIG_BOOTFLAGS_FIRST_ACTIVE_PARTITION=0x03 in its configuration.

  • Create split and part files under meta-project/split directory as follow:

    welma.split
    split   boot   /boot      vfat    overhead=1.1,minsize=4096,boot
    split   sys    /          ext4    overhead=1.1,verity
    split   app    /app       ext4    overhead=1.1,extrasize=4096,verity,systemd
    split   log    /var/log   ext4    overhead=1.3,extrasize=390000,mount=defaults:noexec
    split   var    /var       ext4    overhead=1.3,extrasize=390000,mount=defaults:noexec
    
    migrate /home  /var/home  bind
    
    welma.part
    part   boot   size=50M,update=ab,dev=${DEV_PARTA}:${DEV_PARTB}
    part   sys    size=350M,update=ab,dev=${DEV_PARTC}:${DEV_PARTD}
    part   app    size=50M,version=1.0,update=ab,dev=${DEV_PARTE}:${DEV_PARTF}
    part   log    size=500M,dev=${DEV_PARTG}
    part   var    size=400M,dev=${DEV_PARTH}
    

  • For WIC-based image types, the description file should be structured as follows:

    part --source rawcopy --sourceparams="file=<YOUR-FSBL>"
    
    # bootflags
    part --align 3072 --size 1M
    
    # boot
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.boot.vfat${IMG_SUFFIX_boot}" --align 8192 --fixed-size ${PARTITION_SIZE_boot}
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.boot.vfat${IMG_SUFFIX_boot}" --fixed-size ${PARTITION_SIZE_boot}
    
    # sys
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.sys.ext4${IMG_SUFFIX_sys}" --fixed-size ${PARTITION_SIZE_sys}
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.sys.ext4${IMG_SUFFIX_sys}" --fixed-size ${PARTITION_SIZE_sys}
    
    # app
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.app.ext4${IMG_SUFFIX_app}" --fixed-size ${PARTITION_SIZE_app}
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.app.ext4${IMG_SUFFIX_app}" --fixed-size ${PARTITION_SIZE_app}
    
    # log
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.log.ext4${IMG_SUFFIX_log}" --fixed-size ${PARTITION_SIZE_log}
    
    # var
    part --source rawcopy --sourceparams="file=${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.var.ext4${IMG_SUFFIX_var}" --fixed-size ${PARTITION_SIZE_var}
    
    bootloader --ptable gpt
    

  • Build and flash the image. You can verify the running partition layout in /etc/welma-partitions.conf that should be structured as follows:

    /etc/welma-partitions.conf
    # NAME  MOUNTPOINT      DEVICE-A        DEVICE-B        FLAGS   OPTIONS
    boot    /boot/          /dev/mmcblk0p3  /dev/mmcblk0p4  boot    ro
    app     /app/           /dev/mmcblk0p7  /dev/mmcblk0p8  verity  ro
    log     /var/log/       /dev/mmcblk0p9  -               -       defaults,noexec
    var     /var/           /dev/mmcblk0p10 -               -       defaults,noexec
    sys     /               /dev/mmcblk0p5  /dev/mmcblk0p6  verity  ro
    

🎉 You have successfully implemented your custom partitioning layout

Monolithic rootfs with U-Boot

This section explains how you could configure a monolithic rootfs partition that contains all (kernel, rootfs, /var, ...), with A/B mode update.

Warning

We do not fully support this configuration as we do not test it and it has issues: not compatible with secure boot, /etc/machine-id not correctly handled, read-only vs read-write issues, and other system tweaks would probably be needed to get a fully operational Linux system...

We just keep this section for the record.

This can be achieved as follows:

meta-project/split/welma.split
split   sysro   /       ext4    overhead=1.1,mount=rw
meta-project/split/welma.part
part    sysro   update=ab,dev=/dev/mmcblk0p1:/dev/mmcblk0p2
  • Modify your u-boot recipe as follows:

    recipes-bsp/u-boot/files/distro-bootcmd.env.in
    -imagepath=fitImage
    +imagepath=boot/fitImage
    

  • Ensure that u-boot is configure with CONFIG_FS_EXT4=y

How to Relocate Bootflags

The bootflags are stored as a raw memory segment that must be accessible by:

  • The bootloader (if any)
  • Linux userspace programs (read and write)

Warning

The bootflags partition in UEFI based machines is distinguished by its part-name in the partition table: "bootflags". This name is set in the wks file and should not be changed.

The following parameters can be modified in your global configuration (local.conf or ${MACHINE}.conf):

  • BOOTFLAGS_PATH: path in Linux userspace context. Note that if the path pointed to by BOOTFLAGS_PATH does not exist, Welma will create it and point it to the partition named bootflags (this option offers flexibility so that bootlfags can be used on the boot disk without necessarily knowing how the kernel will enumerate it). In this case, this parameter must be set to a path under /dev/disk (e.g /dev/disk/bootflags).
  • BOOTFLAGS_OFFSET: address of the main bootflags segment (in bytes) within BOOTFLAGS_PATH
  • BOOTFLAGS_OFFSET_COPY: address of the duplicate (in bytes) within BOOTFLAGS_PATH
  • BOOTFLAGS_DEFAULT_SLOTS: default slots for bootflags initialization (e.g 2:4:6). Required for UEFI based machine.

The _OFFSET addresses should point at the beginning of a block (eg. if the eMMC block size is 512, then the addresses must be multiple of 512), in order to minimize chances of corruption in case of any hard reset.

Example:

BOOTFLAGS_PATH ?= "/dev/mmcblk0"
BOOTFLAGS_OFFSET ?= "0x100000"
BOOTFLAGS_OFFSET_COPY ?= "0x100200"

U-Boot

When using U-Boot, you should also provide a configuration aligned with the above:

  • CONFIG_BOOTFLAGS_OFFSET and _COPY:

Example:

CONFIG_CMD_BOOTFLAGS=y
CONFIG_BOOTFLAGS_INTERFACE="mmc"
CONFIG_BOOTFLAGS_DEVICE=0
CONFIG_BOOTFLAGS_OFFSET=0x100000
CONFIG_BOOTFLAGS_OFFSET_COPY=0x100200

To ensure the system can locate the kernel partition when Bootflags are not set (typically at the very first boot), the CONFIG_BOOTFLAGS_FIRST_ACTIVE_PARTITION U-Boot Configuration is used. It should specify the index of the first active user partition, which must correspond to the kernel partition.

Example:

CONFIG_BOOTFLAGS_FIRST_ACTIVE_PARTITION=0x01

To go further

For additional examples on how to write your .split and .part files based on your partitioning scheme, please refer to the meta-demo-partitioning layer.

For more details on Welma's default layout implementation, please refer to the Reference Partition Layout and Boot Sequence page.