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
/etcchanges 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-*.binimage, 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 writeandcfg-backup restorepreserve 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
sysupgradestill work exactly as before.