STRUCT UBIFS_INODE(9)
π struct ubifs_inode(9) π
okay so bestie, we're diving into the Kernel API Manual for struct ubifs_inode and honestly? this one's a whole personality. it's the UBIFS in-memory inode description, and it has main character energy β mutexes, shadow variables, the works. buckle up π
β¨ NAME β¨
struct ubifs_inode β UBIFS in-memory inode description. that's it, that's the vibe π
πΈ SYNOPSIS πΈ
like, here's the whole struct, no cap β every field exactly where it lives:
struct ubifs_inode {
struct inode vfs_inode;
unsigned long long creat_sqnum;
unsigned long long del_cmtno;
unsigned int xattr_size;
unsigned int xattr_cnt;
unsigned int xattr_names;
unsigned int dirty:1;
unsigned int xattr:1;
unsigned int bulk_read:1;
unsigned int compr_type:2;
struct mutex ui_mutex;
struct rw_semaphore xattr_sem;
spinlock_t ui_lock;
loff_t synced_i_size;
loff_t ui_size;
int flags;
pgoff_t last_page_read;
pgoff_t read_in_a_row;
int data_len;
void *data;
#ifdef CONFIG_FS_ENCRYPTION;
struct fscrypt_inode_info *i_crypt_info;
#endif;
};
π¦ Members π¦
okay so let's meet the cast one by one, they all matter, nobody's a side character:
vfs_inodeβ the VFS inode description object. our foundational icon πcreat_sqnumβ sequence number at time of creation. the birthday certificate πdel_cmtnoβ commit number corresponding to the time the inode was deleted, protected byc->commit_sem; note the semicolon, it's part of the packagexattr_sizeβ summarized size of all extended attributes in bytesxattr_cntβ count of extended attributes this inode hasxattr_namesβ sum of lengths of all extended attribute names belonging to this inodedirtyβ non-zero if the inode is dirtyxattrβ non-zero if this is an extended attribute inodebulk_readβ non-zero if bulk-read should be usedcompr_typeβ default compression type used for this inodeui_mutexβ serializes inode write-back with the rest of VFS operations, serializes "clean <-> dirty" state changes, serializes bulk-read, protectsdirty,bulk_read,ui_size, andxattr_size. literally the busiest bouncer at the club π«Άxattr_semβ serilizes write operations (remove|set|create) on xattrui_lockβ protectssynced_i_sizesynced_i_sizeβ synchronized size of inode, i.e. the value of inode size currently stored on the flash; used only for regular file inodesui_sizeβ inode size used by UBIFS when writing to flashflagsβ inode flags (UBIFS_COMPR_FL, etc)last_page_readβ page number of last page read (for bulk read)read_in_a_rowβ number of consecutive pages read in a row (for bulk read)data_lenβ length of the data attached to the inodedataβ inode's datai_crypt_infoβ inode's fscrypt information
π Description π
so why does ui_mutex even exist? two main reasons, bestie, and both are kinda iconic:
reason one π§ β it prevents inodes from being written back while UBIFS is changing them, like when it's in the middle of a VFS operation. this way UBIFS makes sure the inode fields are consistent. for example, in ubifs_rename we change 4 inodes simultaneously, and write-back must not write any of them before we have finished. four inodes at once, no notes π
reason two π β budgeting!! UBIFS has to budget all operations. if an operation is going to mark an inode dirty, it has to allocate budget for this. it cannot just mark it dirty because there is no guarantee there will be enough flash space to write the inode back later. this means UBIFS has to have full control over inode "clean <-> dirty" transitions (and pages actually).
but unfortunately π VFS marks inodes dirty in many places, and it does not ask the file-system if it is allowed to do so (there is a notifier, but it is not enough), i.e., there is no mechanism to synchronize with this. so UBIFS has its own inode dirty flag and its own mutex to serialize "clean <-> dirty" transitions. self-sufficient queen behavior β¨
the synced_i_size field is used to make sure we never write pages which are beyond last synchronized inode size. see ubifs_writepage for more information.
the ui_size is a "shadow" variable for inode->i_size and UBIFS uses ui_size instead of inode->i_size. the reason? UBIFS cannot make sure inode->i_size is always changed under ui_mutex, because it cannot call truncate_setsize with ui_mutex locked, because it would deadlock with ubifs_writepage (see file.c). π all the other inode fields are changed under ui_mutex, so they do not need "shadow" fields. note, one could consider to rework locking and base it on "shadow" fields.
fr fr the whole moral of the story is: locking is hard, shadow fields are the coping mechanism, and deadlocks are the enemy π«Ά
π SEE ALSO π
Kernel file ./fs/ubifs/ubifs.h and the whole squad:
struct ubifs_old_idx(9), struct ubifs_scan_node(9), struct ubifs_scan_leb(9), struct ubifs_gced_idx_leb(9), struct ubifs_unclean_leb(9), struct ubifs_lprops(9), struct ubifs_lpt_lprops(9), struct ubifs_lp_stats(9), struct ubifs_cnode(9), struct ubifs_pnode(9), struct ubifs_nbranch(9), struct ubifs_nnode(9), struct ubifs_lpt_heap(9), struct ubifs_wbuf(9), struct ubifs_bud(9), struct ubifs_jhead(9), struct ubifs_zbranch(9), struct ubifs_znode(9), struct bu_info(9), struct ubifs_node_range(9), struct ubifs_compressor(9), struct ubifs_budget_req(9), struct ubifs_orphan(9), struct ubifs_mount_opts(9), struct ubifs_budg_info(9), struct ubifs_stats_info(9), struct ubifs_info(9), ubifs_check_hash(9), ubifs_check_hmac(9), ubifs_branch_hash(9), ubifs_copy_hash(9), ubifs_auth_node_sz(9)
that's the whole page, go read the entire ubifs header now, iykyk π¦
and that's a wrap, bestie π this gem lives in ./fs/ubifs, dated October 2026, and yes β it still calls itself struct ubifs_inode(9) at the bottom, periodt. πβ¨
π¦ 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