Fixed Partitions, Safe Upgrades: The New Flash Layout

Up until now, upgrading Thingino firmware meant one thing: flash the whole image and hope you remembered to back up your Wi-Fi password. The kernel partition grew and shrank with each build, shifting rootfs to a different offset every time. You could not replace just the kernel or just the root filesystem — any change in size rippled through the layout, and the camera would not boot. So you flashed the whole thing, every time, and then manually restored your config.

No more. The latest firmware introduces fixed-size partitions and a dedicated config backup partition. Partial upgrades work. Your settings survive. Here is what changed and why.

The problem with dynamic partitions

The old layout had two fixed partitions — U-Boot at 256KB and environment at 64KB — and everything after was sized to the exact byte of what the build produced:

mtdparts=...:256k(boot),64k(env),{kernel}k(kernel),{rootfs}k(rootfs),{data}k(data),{flash}k@0(all)

The kernel partition was KERNEL_BIN_SIZE_ALIGNED — as big as the compiled uImage, rounded up to the nearest 64KB erase block. Enable one more driver? The partition grew. Remove a module? It shrank. Rootfs started at a new offset every build. That meant:

  • No partial upgrades. Flashing only the kernel was impossible — a size change would misalign the rootfs that followed it.
  • No safe rootfs updates. The data partition (your JFFS2 overlay holding /etc changes and installed packages) lived right after rootfs. Flash a differently-sized rootfs and you clobbered your data.
  • Every upgrade was “full or nothing.” You uploaded the complete thingino-*.bin image, erased the chip, and started over.

For a device running 24/7 in a ceiling, this was more than an inconvenience. It was the reason people put off updates.

Fixed partitions: predict where everything lives

The new layout pins every partition before rootfs to a universal fixed size — big enough for the largest known case across all supported cameras:

mtdparts=...:256k(boot),64k(env),64k(backup),1600k(kernel),{rootfs}k(rootfs),{data}k(data)
Partition Size Type Contents
mtd0 boot 256KB fixed U-Boot SPL + image
mtd1 env 64KB fixed U-Boot environment
mtd2 backup 64KB fixed config backup (raw)
mtd3 kernel 1600KB fixed uImage
mtd4 rootfs varies dynamic squashfs
mtd5 data varies dynamic JFFS2 overlay

The kernel partition is 1600KB — period. The largest kernel across every camera in the tree compiles to about 1544KB, so 1600KB covers them all with room to spare. Because mtd3 is always the same size, mtd4 (rootfs) always starts at the same offset: 256 + 64 + 64 + 1600 = 1984KB into the flash.

This one change makes partial upgrades safe. The kernel always lands at the same location. Rootfs always starts at the same location. You can flash either independently, and the camera will still boot.

The old virtual all partition that spanned the full chip is gone — it was a convenience for programmer-based flashing but had no role in OTA upgrades and complicated the MTD table.

The backup partition: your settings survive

Between the environment and the kernel sits a new 64KB partition: mtd2, the backup partition. It holds a small tarball of config files that gets written before a flash and restored afterward.

The tool is cfg-backup, and it ships on every Thingino camera:

# Before an upgrade, or any time you want a safety net:
cfg-backup write

# After flashing new firmware:
cfg-backup restore

Without arguments, cfg-backup write reads the manifest at /etc/cfg-backup.list and tars up every path listed. The default manifest covers what you actually care about:

/etc/passwd /etc/shadow               # user accounts
/etc/wpa_supplicant.conf              # WiFi credentials
/etc/TZ /etc/timezone                 # timezone
/etc/dropbear                         # SSH host keys
/root/.ssh/authorized_keys            # SSH access
/etc/thingino.json                    # Thingino settings

You can add your own paths — prudynt.json, telegrambot.json, custom CGI configs — by editing the list. The list file itself is always included in the backup, so a restore gives you back the exact manifest that was used.

The partition holds a 64-byte text header (magic THNG_BCKUP, byte count, MD5 hash) followed by an uncompressed tar archive. At 64KB minus the header, you get about 65,472 bytes of payload — enough for every config file on a typical camera with room to spare. The header MD5 catches corruption; cfg-backup restore refuses to extract anything that does not match.

Partial upgrades: flash only what changed

Fixed offsets plus the backup partition unlock a new set of make targets. Each one uploads only the partition files that are needed and flashes them directly:

make ota-kernel  IP=192.168.88.10     # kernel only --- ~1.6MB transfer
make ota-uboot   IP=192.168.88.10     # bootloader + env
make ota-rootfs  IP=192.168.88.10     # rootfs + data
make ota-upgrade IP=192.168.88.10     # rootfs + data WITH config backup
make ota         IP=192.168.88.10     # full firmware (unchanged)

ota-upgrade is the everyday workhorse: it backs up your config to the backup partition, flashes the new rootfs and data partitions, and restores your settings — all without touching the kernel or bootloader. A kernel experiment stops being a 16MB upload; it is a 1.6MB transfer that completes in seconds.

The camera-side script that handles partial flashes is flash-ota. It resolves MTD names from /proc/mtd, stops the streamer, clones busybox to a tmpfs (so it survives the rootfs being erased out from under it), remounts / read-only, and flashes each partition directly to its MTD device. 85 lines of shell. When it is done, the camera reboots.

For full-firmware upgrades, the existing sysupgrade utility remains. It picks up the same backup integration when you pass -B:

sysupgrade -B -f                    # full upgrade from GitHub, config backed up
sysupgrade -B thingino-camera.bin   # local image, same deal

What this means for your workflow

Before After
Every upgrade = full flash Flash only what changed
Kernel size shifts rootfs offset Kernel fixed at 1600KB
Config manually backed up (if at all) cfg-backup to dedicated partition
make ota is the only target ota-kernel, ota-uboot, ota-rootfs, ota-upgrade
Kernel experiments are 16MB transfers 1.6MB, seconds
No backup partition existed 64KB raw partition with verified tar

If you are on an older Thingino build, the first upgrade to a fixed-layout firmware will be a full flash — the partition table itself is changing. After that, every subsequent update can be a partial one.

What you learned

  • The flash layout is now boot(256K) -> env(64K) -> backup(64K) -> kernel(1600K) -> rootfs -> data.
  • Fixed kernel partition size means rootfs always starts at the same offset, making partial upgrades safe for the first time.
  • The backup partition (mtd2) holds a verified tarball of your config files.
  • cfg-backup write and cfg-backup restore preserve settings across flashes.
  • Partial OTA targets (ota-kernel, ota-uboot, ota-rootfs, ota-upgrade) replace the old all-or-nothing upgrade model.
  • The full firmware image and sysupgrade still work exactly as before.