Skip to content

Add UBI/UBIFS-aware backup for NAND cameras #141

@widgetii

Description

@widgetii

Problem

ipctool's backup command reads raw MTD partitions via /dev/mtdblockN. On NAND cameras with UBI/UBIFS, this produces dumps that cannot be safely restored to a different chip (or even the same chip after bad blocks change), because:

  1. Raw MTD dumps include UBI erase counter (EC) and volume ID (VID) headers that encode the physical-to-logical block mapping for the specific chip's bad block layout
  2. Writing such dumps via nand write skips bad blocks, shifting all data — UBI's internal mapping becomes inconsistent
  3. Result: UBIFS finds corrupted data and the camera fails to boot

This was proven on a hi3516av200 camera (128MB SPI NAND, 5 UBI volumes). Raw MTD backup + restore caused:

UBIFS error: bad CRC: calculated 0xde13f664, read 0xb30f1910
Kernel panic - VFS: Unable to mount root fs

The fix: dump UBI volumes (/dev/ubiX_Y) instead of raw MTD, and restore via ubi write which handles bad block mapping internally. Now implemented in defib and documented in the NAND/UBI restore guide.

Current behavior

backup.c:49-61cb_mtd_backup() opens /dev/mtdblockN and mmap's raw MTD data. mtd.c:104-121open_mtdblock() reads raw NAND including UBI headers. Zero UBI awareness (grep -ri ubi src/ returns nothing).

Proposed changes

1. Detect UBI partitions during backup

In cb_mtd_info() (mtd.c:187), check if the partition has UBI attached by scanning /sys/class/ubi/:

// Check /sys/class/ubi/ubiN/mtd_num to find which UBI device
// is attached to each MTD partition
int find_ubi_for_mtd(int mtd_num) {
    DIR *d = opendir("/sys/class/ubi");
    if (!d) return -1;
    struct dirent *de;
    while ((de = readdir(d))) {
        if (strncmp(de->d_name, "ubi", 3) != 0) continue;
        if (strchr(de->d_name, '_')) continue; // skip ubiN_V entries
        char path[128];
        snprintf(path, sizeof(path), "/sys/class/ubi/%s/mtd_num", de->d_name);
        FILE *f = fopen(path, "r");
        if (f) {
            int num;
            if (fscanf(f, "%d", &num) == 1 && num == mtd_num) {
                fclose(f); closedir(d);
                int ubi_num;
                sscanf(de->d_name, "ubi%d", &ubi_num);
                return ubi_num;
            }
            fclose(f);
        }
    }
    closedir(d);
    return -1;
}

2. Dump UBI volumes instead of raw MTD

In cb_mtd_backup() (backup.c:49), when a partition has UBI, read from /dev/ubiN_V instead of /dev/mtdblockN:

int ubi_num = find_ubi_for_mtd(i);
if (ubi_num >= 0) {
    // Read /dev/ubiN_0 (first volume)
    char vol_path[64];
    snprintf(vol_path, sizeof(vol_path), "/dev/ubi%d_0", ubi_num);
    int fd = open(vol_path, O_RDONLY);
    // Get size from /sys/class/ubi/ubiN_0/data_bytes
    // Read volume data (UBIFS image, no UBI headers)
    // ...
} else {
    // Standard raw MTD dump (current behavior)
    char *addr = open_mtdblock(i, &fd, mtd->size, 0);
}

3. Add UBI metadata to YAML

Record which partitions are UBI volumes vs raw MTD. This is essential for proper restore:

rom:
  - type: nand
    block: 128K
    partitions:
      - name: boot
        size: 0x100000
        sha1: b77adba9
        dump_type: raw           # NEW
      - name: rootfs
        size: 0x800000
        dump_type: ubifs          # NEW
        ubi_device: 0             # NEW
        ubi_volume: 0             # NEW
        volume_name: rootfs       # NEW (needed for restore via ubi write)
        data_bytes: 5206016       # NEW (actual volume data size)

Useful sysfs paths:

  • /sys/class/ubi/ubiN/mtd_num — which MTD this UBI is attached to
  • /sys/class/ubi/ubiN_V/name — volume name (e.g., "rootfs")
  • /sys/class/ubi/ubiN_V/data_bytes — volume data size
  • /sys/class/ubi/ubiN_V/type — "dynamic" or "static"

4. Support UBI restore

In restore_backup() (backup.c:437), check dump_type and use appropriate method:

  • dump_type: raw → standard MTD erase+write (current behavior)
  • dump_type: ubifs → UBI-aware restore:
    // Detach UBI, format, reattach, create volume, write UBIFS image
    ubidetach -m MTD_NUM
    ubiformat /dev/mtdN -y
    ubiattach -m MTD_NUM
    ubimkvol /dev/ubiN -N VOLNAME -s SIZE
    ubiupdatevol /dev/ubiN_0 IMAGE_FILE
    These commands may need to be bundled with ipctool or called via system().

5. Files to modify

File Change
src/mtd.c Add find_ubi_for_mtd(), enumerate UBI volumes in cb_mtd_info()
src/mtd.h Add UBI declarations
src/backup.c Modify cb_mtd_backup() for UBI volumes, add dump_type to YAML, UBI-aware restore
src/backup.h Add UBI metadata fields

Why this matters

NAND cameras are increasingly common (hi3516av200, hi3516dv300, hi3519v101, etc.). Without UBI-aware backups:

  • Users cannot safely restore vendor firmware after trying OpenIPC
  • Backups uploaded to the cloud are chip-specific and unusable on replacement hardware
  • Camera recovery requires serial boot tools instead of simple in-system restore

See the defib NAND/UBI restore guide for full context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions