#ifndef __EROFS_FS_H
#define __EROFS_FS_H
#define EROFS_SUPER_OFFSET 1024
#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001
#define EROFS_FEATURE_COMPAT_MTIME 0x00000002
#define EROFS_FEATURE_COMPAT_XATTR_FILTER 0x00000004
#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING 0x00000001
#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
#define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002
#define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004
#define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE 0x00000008
#define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 0x00000008
#define EROFS_FEATURE_INCOMPAT_ZTAILPACKING 0x00000010
#define EROFS_FEATURE_INCOMPAT_FRAGMENTS 0x00000020
#define EROFS_FEATURE_INCOMPAT_DEDUPE 0x00000020
#define EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES 0x00000040
#define EROFS_ALL_FEATURE_INCOMPAT \
(EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \
EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \
EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \
EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \
EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \
EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \
EROFS_FEATURE_INCOMPAT_FRAGMENTS | \
EROFS_FEATURE_INCOMPAT_DEDUPE | \
EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES)
#define EROFS_SB_EXTSLOT_SIZE 16
struct erofs_deviceslot {
u8 tag[64];
__le32 blocks;
__le32 mapped_blkaddr;
u8 reserved[56];
};
#define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot)
struct erofs_super_block {
__le32 magic;
__le32 checksum;
__le32 feature_compat;
__u8 blkszbits;
__u8 sb_extslots;
__le16 root_nid;
__le64 inos;
__le64 build_time;
__le32 build_time_nsec;
__le32 blocks;
__le32 meta_blkaddr;
__le32 xattr_blkaddr;
__u8 uuid[16];
__u8 volume_name[16];
__le32 feature_incompat;
union {
__le16 available_compr_algs;
__le16 lz4_max_distance;
} __packed u1;
__le16 extra_devices;
__le16 devt_slotoff;
__u8 dirblkbits;
__u8 xattr_prefix_count;
__le32 xattr_prefix_start;
__le64 packed_nid;
__u8 xattr_filter_reserved;
__u8 reserved2[23];
};
enum {
EROFS_INODE_FLAT_PLAIN = 0,
EROFS_INODE_COMPRESSED_FULL = 1,
EROFS_INODE_FLAT_INLINE = 2,
EROFS_INODE_COMPRESSED_COMPACT = 3,
EROFS_INODE_CHUNK_BASED = 4,
EROFS_INODE_DATALAYOUT_MAX
};
static inline bool erofs_inode_is_data_compressed(unsigned int datamode)
{
return datamode == EROFS_INODE_COMPRESSED_COMPACT ||
datamode == EROFS_INODE_COMPRESSED_FULL;
}
#define EROFS_I_VERSION_MASK 0x01
#define EROFS_I_DATALAYOUT_MASK 0x07
#define EROFS_I_VERSION_BIT 0
#define EROFS_I_DATALAYOUT_BIT 1
#define EROFS_I_ALL_BIT 4
#define EROFS_I_ALL ((1 << EROFS_I_ALL_BIT) - 1)
#define EROFS_CHUNK_FORMAT_BLKBITS_MASK 0x001F
#define EROFS_CHUNK_FORMAT_INDEXES 0x0020
#define EROFS_CHUNK_FORMAT_ALL \
(EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES)
#define EROFS_INODE_LAYOUT_COMPACT 0
#define EROFS_INODE_LAYOUT_EXTENDED 1
struct erofs_inode_chunk_info {
__le16 format;
__le16 reserved;
};
union erofs_inode_i_u {
__le32 compressed_blocks;
__le32 raw_blkaddr;
__le32 rdev;
struct erofs_inode_chunk_info c;
};
struct erofs_inode_compact {
__le16 i_format;
__le16 i_xattr_icount;
__le16 i_mode;
__le16 i_nlink;
__le32 i_size;
__le32 i_reserved;
union erofs_inode_i_u i_u;
__le32 i_ino;
__le16 i_uid;
__le16 i_gid;
__le32 i_reserved2;
};
struct erofs_inode_extended {
__le16 i_format;
__le16 i_xattr_icount;
__le16 i_mode;
__le16 i_reserved;
__le64 i_size;
union erofs_inode_i_u i_u;
__le32 i_ino;
__le32 i_uid;
__le32 i_gid;
__le64 i_mtime;
__le32 i_mtime_nsec;
__le32 i_nlink;
__u8 i_reserved2[16];
};
struct erofs_xattr_ibody_header {
__le32 h_name_filter;
__u8 h_shared_count;
__u8 h_reserved2[7];
__le32 h_shared_xattrs[];
};
#define EROFS_XATTR_INDEX_USER 1
#define EROFS_XATTR_INDEX_POSIX_ACL_ACCESS 2
#define EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
#define EROFS_XATTR_INDEX_TRUSTED 4
#define EROFS_XATTR_INDEX_LUSTRE 5
#define EROFS_XATTR_INDEX_SECURITY 6
#define EROFS_XATTR_LONG_PREFIX 0x80
#define EROFS_XATTR_LONG_PREFIX_MASK 0x7f
#define EROFS_XATTR_FILTER_BITS 32
#define EROFS_XATTR_FILTER_DEFAULT UINT32_MAX
#define EROFS_XATTR_FILTER_SEED 0x25BBE08F
struct erofs_xattr_entry {
__u8 e_name_len;
__u8 e_name_index;
__le16 e_value_size;
char e_name[];
};
struct erofs_xattr_long_prefix {
__u8 base_index;
char infix[];
};
static inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount)
{
if (!i_xattr_icount)
return 0;
return sizeof(struct erofs_xattr_ibody_header) +
sizeof(__u32) * (le16_to_cpu(i_xattr_icount) - 1);
}
#define EROFS_XATTR_ALIGN(size) round_up(size, sizeof(struct erofs_xattr_entry))
static inline unsigned int erofs_xattr_entry_size(struct erofs_xattr_entry *e)
{
return EROFS_XATTR_ALIGN(sizeof(struct erofs_xattr_entry) +
e->e_name_len + le16_to_cpu(e->e_value_size));
}
#define EROFS_NULL_ADDR -1
#define EROFS_BLOCK_MAP_ENTRY_SIZE sizeof(__le32)
struct erofs_inode_chunk_index {
__le16 advise;
__le16 device_id;
__le32 blkaddr;
};
struct erofs_dirent {
__le64 nid;
__le16 nameoff;
__u8 file_type;
__u8 reserved;
} __packed;
#define EROFS_NAME_LEN 255
#define Z_EROFS_PCLUSTER_MAX_SIZE (1024 * 1024)
enum {
Z_EROFS_COMPRESSION_LZ4 = 0,
Z_EROFS_COMPRESSION_LZMA = 1,
Z_EROFS_COMPRESSION_DEFLATE = 2,
Z_EROFS_COMPRESSION_MAX
};
#define Z_EROFS_ALL_COMPR_ALGS ((1 << Z_EROFS_COMPRESSION_MAX) - 1)
struct z_erofs_lz4_cfgs {
__le16 max_distance;
__le16 max_pclusterblks;
u8 reserved[10];
} __packed;
struct z_erofs_lzma_cfgs {
__le32 dict_size;
__le16 format;
u8 reserved[8];
} __packed;
#define Z_EROFS_LZMA_MAX_DICT_SIZE (8 * Z_EROFS_PCLUSTER_MAX_SIZE)
struct z_erofs_deflate_cfgs {
u8 windowbits;
u8 reserved[5];
} __packed;
#define Z_EROFS_ADVISE_COMPACTED_2B 0x0001
#define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002
#define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004
#define Z_EROFS_ADVISE_INLINE_PCLUSTER 0x0008
#define Z_EROFS_ADVISE_INTERLACED_PCLUSTER 0x0010
#define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER 0x0020
#define Z_EROFS_FRAGMENT_INODE_BIT 7
struct z_erofs_map_header {
union {
__le32 h_fragmentoff;
struct {
__le16 h_reserved1;
__le16 h_idata_size;
};
};
__le16 h_advise;
__u8 h_algorithmtype;
__u8 h_clusterbits;
};
enum {
Z_EROFS_LCLUSTER_TYPE_PLAIN = 0,
Z_EROFS_LCLUSTER_TYPE_HEAD1 = 1,
Z_EROFS_LCLUSTER_TYPE_NONHEAD = 2,
Z_EROFS_LCLUSTER_TYPE_HEAD2 = 3,
Z_EROFS_LCLUSTER_TYPE_MAX
};
#define Z_EROFS_LI_LCLUSTER_TYPE_BITS 2
#define Z_EROFS_LI_LCLUSTER_TYPE_BIT 0
#define Z_EROFS_LI_PARTIAL_REF (1 << 15)
#define Z_EROFS_LI_D0_CBLKCNT (1 << 11)
struct z_erofs_lcluster_index {
__le16 di_advise;
__le16 di_clusterofs;
union {
__le32 blkaddr;
__le16 delta[2];
} di_u;
};
#define Z_EROFS_FULL_INDEX_ALIGN(end) \
(ALIGN(end, 8) + sizeof(struct z_erofs_map_header) + 8)
static inline void erofs_check_ondisk_layout_definitions(void)
{
const __le64 fmh = *(__le64 *)&(struct z_erofs_map_header) {
.h_clusterbits = 1 << Z_EROFS_FRAGMENT_INODE_BIT
};
BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
BUILD_BUG_ON(sizeof(struct erofs_inode_compact) != 32);
BUILD_BUG_ON(sizeof(struct erofs_inode_extended) != 64);
BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_info) != 4);
BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) != 8);
BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
BUILD_BUG_ON(sizeof(struct z_erofs_lcluster_index) != 8);
BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) !=
sizeof(struct z_erofs_lcluster_index));
BUILD_BUG_ON(sizeof(struct erofs_deviceslot) != 128);
BUILD_BUG_ON(BIT(Z_EROFS_LI_LCLUSTER_TYPE_BITS) <
Z_EROFS_LCLUSTER_TYPE_MAX - 1);
BUILD_BUG_ON(__builtin_constant_p(fmh) ?
fmh != cpu_to_le64(1ULL << 63) : 0);
}
#endif