STRUCT UBI_VID_HDR(9)
πΈ struct ubi_vid_hdr β the manual page bestie π
okay so this is the kernel API manual page for struct ubi_vid_hdr, and it's literally the on-flash UBI volume identifier header. bestie, it's the little name-tag the flash wears so UBI knows which volume and which eraseblock it's looking at π
β¨ SYNOPSIS β¨
here's the whole struct, copy it exactly, don't be weird about it:
struct ubi_vid_hdr {
__be32 magic;
__u8 version;
__u8 vol_type;
__u8 copy_flag;
__u8 compat;
__be32 vol_id;
__be32 lnum;
__u8 padding1[4];
__be32 data_size;
__be32 used_ebs;
__be32 data_pad;
__be32 data_crc;
__u8 padding2[4];
__be64 sqnum;
__u8 padding3[12];
__be32 hdr_crc;
};
π¦ Members π¦
field-by-field, no skips, we're doing all of them π
magicβ the volume identifier header magic number (UBI_VID_HDR_MAGIC)versionβ the UBI implementation version that's supposed to accept this UBI image (UBI_VERSION)vol_typeβ the volume type (UBI_VID_DYNAMICorUBI_VID_STATIC)copy_flagβ says whether this logical eraseblock got copied from another physical eraseblock (for wear-leveling reasons, iykyk)compatβ the compatibility of this volume (0,UBI_COMPAT_DELETE,UBI_COMPAT_IGNORE,UBI_COMPAT_PRESERVE, orUBI_COMPAT_REJECT)vol_idβ ID of this volumelnumβ logical eraseblock numberpadding1β reserved for future, zeroesdata_sizeβ how many bytes of data this logical eraseblock containsused_ebsβ total number of used logical eraseblocks in this volumedata_padβ how many bytes at the end of this physical eraseblock are not useddata_crcβ CRC checksum of the data stored in this logical eraseblockpadding2β reserved for future, zeroessqnumβ sequence numberpadding3β reserved for future, zeroeshdr_crcβ volume identifier header CRC checksum
π Description π
π§ the sqnum tea β
sqnum is the value of the global sequence counter at the exact moment this VID header was created. the global sequence counter gets incremented every single time UBI writes a new VID header to the flash β like, when it maps a logical eraseblock to a new physical eraseblock. it's an unsigned 64-bit integer and we just assume it never overflows (manifesting that π). sqnum is the thing that lets UBI tell apart older and newer versions of logical eraseblocks β¨
π why are there two PEBs for one LEB (the drama)
there are 2 situations where more than one physical eraseblock can correspond to the same logical eraseblock β meaning they have the same vol_id and lnum values in the volume identifier header. picture a logical eraseblock L mapped to physical eraseblock P. so:
- because UBI may erase physical eraseblocks asynchronously, this whole situation is possible: L gets asynchronously erased, so P is scheduled for erasure, then L is written to β i.e. mapped to another physical eraseblock P1 β so P1 is written to, and then an unclean reboot happens. result? there are 2 physical eraseblocks P and P1 corresponding to the same logical eraseblock L. but P1 has a greater sequence number, so UBI picks P1 when it attaches the flash π
- from time to time UBI moves logical eraseblocks to other physical eraseblocks for wear-leveling reasons. if, for example, UBI moves L from P to P1, and an unclean reboot happens before P is physically erased, there are two physical eraseblocks P and P1 corresponding to L, and UBI has to select one of them when the flash is attached. the
sqnumfield says which PEB is the original (obviously P will have the lowersqnum) and which is the copy. but it is not enough to just select the physical eraseblock with the higher sequence number, because the unclean reboot could have happened in the middle of the copying process, so the data in P is corrupted. it's also not enough to just select the physical eraseblock with the lower sequence number, because the data there may be old (consider a case where more data was added to P1 after the copying). moreover, the unclean reboot may happen when the erasure of P was just started, so it results in unstable P β which is "mostly" OK, but still has unstable bits π
π«Ά the copy_flag + data_crc combo
UBI uses the copy_flag field to indicate that this logical eraseblock is a copy. UBI also calculates the data CRC when the data is moved and stores it in the data_crc field of the copy (P1). so when UBI needs to pick one physical eraseblock out of two (P or P1), it examines the copy_flag of the newer one (P1). if it's cleared, the situation is simple and the newer one gets picked. if it's set, the data CRC of the copy (P1) gets examined. if the CRC checksum is correct, this physical eraseblock is selected (P1). otherwise the older one (P) is selected β¨
π user volumes vs internal volumes
there are 2 sorts of volumes in UBI: user volumes and internal volumes. internal volumes are not seen from outside and are used for various internal UBI purposes. in this implementation there's only one internal volume β the layout volume. internal volumes are the main mechanism of UBI extensions. for example, in future someone might introduce a journal internal volume. internal volumes have their own reserved range of IDs π
π the compat field
compat is only used for internal volumes and contains the "degree of their compatibility". it's always zero for user volumes. this field provides a mechanism to introduce UBI extensions and still be compatible with older UBI binaries. for example, if someone introduced a journal in future, he would probably use UBI_COMPAT_DELETE compatibility for the journal volume. and in this case, older UBI binaries, which know nothing about the journal volume, would just delete this volume and work perfectly fine. this is similar to what Ext2fs does when it's fed by an Ext3fs image:
- it just ignores the Ext3fs journal.
π₯ the data_crc field, more precisely
data_crc contains the CRC checksum of the contents of the logical eraseblock if this is a static volume. in the case of dynamic volumes, it does not contain the CRC checksum as a rule. the only exception is when the data of the physical eraseblock was moved by the wear-leveling sub-system β then the wear-leveling sub-system calculates the data CRC and stores it in the data_crc field. and of course, copy_flag is set in this case π
π the data_size field
data_size is used only for static volumes, because UBI has to know how many bytes of data are stored in this eraseblock. for dynamic volumes, this field usually contains zero. the only exception is when the data of the physical eraseblock was moved to another physical eraseblock for wear-leveling reasons β in this case UBI calculates the CRC checksum of the contents and uses both the data_crc and data_size fields. in this case, the data_size field contains the data size β
πΈ the used_ebs field
used_ebs is used only for static volumes and indicates how many eraseblocks the data of the volume takes. for dynamic volumes this field is not used and always contains zero π¦
π the data_pad field
data_pad is calculated when volumes are created using the alignment parameter. so, effectively, the data_pad field reduces the size of logical eraseblocks of this volume. this is very handy when one uses block-oriented software (say, cramfs) on top of the UBI volume. iconic, honestly π§
π SEE ALSO π
kernel file ./drivers/mtd/ubi/ubi-media.h and friends: struct ubi_ec_hdr(9), struct ubi_vtbl_record(9), struct ubi_fm_sb(9), struct ubi_fm_hdr(9), struct ubi_fm_scan_pool(9), struct ubi_fm_ec(9), struct ubi_fm_volhdr(9), struct ubi_fm_eba(9) β go read them, they're all in their flop era together π«Ά
and that's the whole page, no cap. this one came out of./drivers/mtd/ubi, dated October 2026, and the manual page isstruct ubi_vid_hdr(9). mwah, go touch some flash ππΈ
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms