Blog

Partition layout design for embedded devices to enable image-based updates

Software updates for embedded devices are typically deployed as full image updates. There are many design considerations take into account in the partition table layout to enable full image updates, including

  • Do configuration settings need to be preserved during updates?
  • Does the device storage controller support wear leveling or should this be handled by the operating system?
  • Will the bootloader and the kernel need to be updated, or only rootfs?
  • How should partial or failed updates be handled?
  • Is a physical "factory reset" option desired?

There was a discussion about these issues on the OpenEmbedded mailing list (thread no longer available in archives), especially issues with preserving configuration settings. We'll touch upon some of the other issues in this post.

Wear leveling: block vs raw storage

The purpose of wear leveling is to extend the lifetime of the device storage by distributing writes evenly across the storage medium. This is important for flash-based storage, often found in embedded devices, because each storage segment can only support a fairly limited amount of writes.

Storage devices may incorporate wear leveling transparently as part of the storage controller logic, in which case this problem is taken care of by the storage device manufacturer. This is the case for most mid- to high-end storage devices. For example, all SD cards have a storage controller that takes wear leveling into account.

Many cheaper or older storage devices do not have wear leveling built in, however, and then wear leveling should be handled at the operating system level. This type of storage is often referred to as "raw flash", and in Linux it makes use of the Memory Technology Device (MTD) subsystem to implement wear leveling.

When working with raw flash devices, Unsorted Block Images (UBI) (which is similar in purpose to Logical Volume Manager (LVM)) and UBIFS can be used to implement wear leveling.

Updating rootfs, kernel, and bootloader

What needs to be updated also impacts the design of the partition layout. The reason is that we need a copy of the elements that we would like to update in case there is a problem when installing the update - like a sudden power loss. The process is then basically:

  1. Install and verify the update.
  2. Reboot.
  3. If there is an issue booting, reboot into the previous software environment.

rootfs needs updates the most frequently, because it holds the majority of the software. It also incurs the lowest risk of updating. The Linux kernel requires updates some times, when there are bugs or enhancements that are desirable to deploy. But as Linux is fairly stable and fundamental to the operation of the device, updates to it are typically less frequent than rootfs. Finally, the bootloader is very rarely changed. It contains the least amount of logic and the smallest problem with the bootloader may render the entire device broken.

Enabling safe rootfs and kernel updates

The following partition table layout will enable safe updates of rootfs and the kernel, as it keeps separate copies of them and allows using the update process outlined above. Note that this layout assumes that the update is carried out from user space, not from the bootloader.

Partition table layout enabling image-based updates of kernel and rootfs

There are more details to be considered before implementing, like managing configuration settings and which file systems to choose. But this should set us off in the right direction with respect to the partition table layout for image-based software updates!