Extended Attributes (Xattrs)#
EROFS supports Extended Attributes
(xattr(7)) which are
name:value pairs associated permanently with inodes since the initial Linux
5.4 version.
Superblock Fields for Xattr Support#
The core superblock format is defined in Superblock. This section lists the extended fields dedicated to the xattr features.
Offset |
Size |
Type |
Name |
Description |
|---|---|---|---|---|
0x08 |
4 |
|
|
Compatible feature flags; see Xattr Feature Flags |
0x2C |
4 |
|
|
Start block address of the shared xattr area; see Shared Xattr Area |
0x50 |
4 |
|
|
Incompatible feature flags; see Xattr Feature Flags |
0x5B |
1 |
|
|
Number of long xattr name prefixes; valid when |
0x5C |
4 |
|
|
Location of the long xattr prefix table; valid when |
0x60 |
8 |
|
|
Packed inode NID. Relevant when long xattr prefixes are embedded in the packed inodeโs data region |
0x68 |
1 |
|
|
Must be 0 for the xattr Bloom filter to operate; see Xattr Filter |
0x69 |
1 |
|
|
Long-prefix table index used by image-share xattrs; valid when both |
0x80 |
8 |
|
|
Metabox inode NID. Relevant when shared xattrs or long xattr prefixes are stored in the metabox inodeโs data region |
Xattr Feature Flags#
The following superblock feature bits are directly relevant to xattr support.
feature_compat Bits#
Bit mask |
Name |
Description |
|---|---|---|
|
|
Enables the per-inode xattr Bloom filter described in Xattr Filter |
|
|
Stores the shared xattr area in the metabox inodeโs decoded data region instead of at |
|
|
Stores the long xattr prefix table as a standalone region; valid when |
|
|
Enables image-share xattrs. |
feature_incompat Bits#
Bit mask |
Name |
Description |
|---|---|---|
|
|
Enables the long xattr prefix table described in Long Xattr Name Prefixes |
Inode Fields for Xattr Support#
The full compact and extended inode layouts are defined in Inodes. For xattr support, both inode variants share the same feature-specific field:
Offset |
Size |
Type |
Name |
Description |
|---|---|---|---|---|
0x02 |
2 |
|
|
When non-zero, the inline xattr region size is |
Two storage classes exist:
Inline xattrs: stored directly in the metadata block immediately following the inode body (and any inline data tail). They are private to the inode and encoded as a sequence of xattr entry records within the inline xattr region described by
i_xattr_icount.Shared xattrs: stored once in the global shared xattr area. An inode references a shared entry through a 4-byte index stored immediately after the fixed 12-byte inline xattr header. Multiple inodes that carry an identical xattr (same name and value) can reference the same shared entry, avoiding redundant per-inode copies.
To further reduce storage overhead for xattrs whose names share a common prefix
(for example trusted.overlay.* or security.ima.*), EROFS supports a long xattr
prefix table (EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES). Each prefix entry records a
base_index that refers to one of the standard short namespace prefixes and an
additional infix string. An xattr entry whose e_name_index selects a long prefix
stores only the suffix that follows the full reconstructed prefix, rather than
repeating the prefix in every entry.
Inline Xattr Region Layout#
The inline xattr region immediately follows the inode body (at a 4-byte aligned
offset). Its total size is (i_xattr_icount - 1) * 4 + 12 bytes, where 12 is the
fixed size of the inline xattr body header. The region is structured as:
The Inline Xattr Body Header (12 bytes, fixed).
h_shared_countร 4-byte shared xattr index values.Zero or more Xattr Entry Record (inline entries).
Inline Xattr Body Header#
Offset |
Size |
Type |
Name |
Description |
|---|---|---|---|---|
0x00 |
4 |
|
|
Inverted Bloom filter over xattr names; valid when |
0x04 |
1 |
|
|
Number of shared xattr index entries |
0x05 |
7 |
|
reserved |
Reserved; must be 0 |
Xattr Entry Record#
Each inline or shared xattr entry has the following layout:
Offset |
Size |
Type |
Name |
Description |
|---|---|---|---|---|
0x00 |
1 |
|
|
Length of the name suffix in bytes |
0x01 |
1 |
|
|
Namespace index (maps to a prefix string); see below |
0x02 |
2 |
|
|
Length of the value in bytes |
Immediately following the 4-byte xattr entry header: e_name_len bytes of name
suffix, then e_value_size bytes of value. The entire entry (header + name + value)
is padded to a 4-byte boundary.
e_name_index Namespace Mapping#
Rather than storing the full namespace prefix string in every entry, EROFS encodes
the xattr namespace prefix as a 1-byte index. Bit 7 of e_name_index is the
EROFS_XATTR_LONG_PREFIX flag. When set, the lower 7 bits index into the long
xattr name prefix table (see Long Xattr Name Prefixes).
When clear, the full byte selects one of the built-in short namespace prefixes:
Value |
Prefix |
|---|---|
1 |
|
2 |
|
3 |
|
4 |
|
6 |
|
Long Xattr Name Prefixes#
This section applies when EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES is set.
When this feature is set, a table of xattr_prefix_count prefix entries is
present; see Prefix Table Placement for where that table is stored.
Each entry has the following fixed header, padded together with the
variable-length infix payload to a 4-byte boundary:
Offset |
Size |
Type |
Name |
Description |
|---|---|---|---|---|
0x00 |
2 |
|
|
Byte length of the following content: |
0x02 |
1 |
|
|
Built-in short namespace prefix index (see e_name_index Namespace Mapping) |
The variable-length infix bytes begin at offset 0x03. Their length is
size - 1, and they are not null-terminated.
The full reconstructed prefix is the concatenation of the short prefix indicated by
base_index and the infix bytes. An xattr entry using a long prefix stores only
the name suffix after the reconstructed prefix; e_name_len counts only those suffix
bytes.
For example, an xattr named trusted.overlay.opaque can be represented with
base_index = 4 (trusted.) and infix = "overlay.", yielding the full prefix
trusted.overlay.; the stored name suffix is opaque with e_name_len = 6.
Prefix Table Placement#
The xattr prefix table start offset is recorded in xattr_prefix_start.
The table may be:
embedded in the metabox or packed inodeโs data region when
EROFS_FEATURE_COMPAT_PLAIN_XATTR_PFXis not set; orstored in a standalone region when
EROFS_FEATURE_COMPAT_PLAIN_XATTR_PFXis set.
Xattr Filter#
This section applies when EROFS_FEATURE_COMPAT_XATTR_FILTER is set.
When this feature is set, h_name_filter in the inline xattr body header holds a
32-bit inverted Bloom filter over the inodeโs xattr names. Each bit position
corresponds to one hash bucket:
A bit value of 1 guarantees that no xattr present on this inode hashes to that bucket, so the queried name is definitely absent.
A bit value of 0 means a matching xattr may exist and a full scan is required.
When xattr_filter_reserved in the superblock is non-zero, the Bloom filter is
disabled unconditionally for all inodes in the image.