162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * EROFS (Enhanced ROM File System) on-disk format definition
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017-2018 HUAWEI, Inc.
662306a36Sopenharmony_ci *             https://www.huawei.com/
762306a36Sopenharmony_ci * Copyright (C) 2021, Alibaba Cloud
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#ifndef __EROFS_FS_H
1062306a36Sopenharmony_ci#define __EROFS_FS_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define EROFS_SUPER_OFFSET      1024
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define EROFS_FEATURE_COMPAT_SB_CHKSUM          0x00000001
1562306a36Sopenharmony_ci#define EROFS_FEATURE_COMPAT_MTIME              0x00000002
1662306a36Sopenharmony_ci#define EROFS_FEATURE_COMPAT_XATTR_FILTER	0x00000004
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
2062306a36Sopenharmony_ci * be incompatible with this kernel version.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING	0x00000001
2362306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS	0x00000002
2462306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER	0x00000002
2562306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE	0x00000004
2662306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE	0x00000008
2762306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2	0x00000008
2862306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_ZTAILPACKING	0x00000010
2962306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_FRAGMENTS	0x00000020
3062306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_DEDUPE		0x00000020
3162306a36Sopenharmony_ci#define EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES	0x00000040
3262306a36Sopenharmony_ci#define EROFS_ALL_FEATURE_INCOMPAT		\
3362306a36Sopenharmony_ci	(EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \
3462306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
3562306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \
3662306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \
3762306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \
3862306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \
3962306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \
4062306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_FRAGMENTS | \
4162306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_DEDUPE | \
4262306a36Sopenharmony_ci	 EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define EROFS_SB_EXTSLOT_SIZE	16
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct erofs_deviceslot {
4762306a36Sopenharmony_ci	u8 tag[64];		/* digest(sha256), etc. */
4862306a36Sopenharmony_ci	__le32 blocks;		/* total fs blocks of this device */
4962306a36Sopenharmony_ci	__le32 mapped_blkaddr;	/* map starting at mapped_blkaddr */
5062306a36Sopenharmony_ci	u8 reserved[56];
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci#define EROFS_DEVT_SLOT_SIZE	sizeof(struct erofs_deviceslot)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* erofs on-disk super block (currently 128 bytes) */
5562306a36Sopenharmony_cistruct erofs_super_block {
5662306a36Sopenharmony_ci	__le32 magic;           /* file system magic number */
5762306a36Sopenharmony_ci	__le32 checksum;        /* crc32c(super_block) */
5862306a36Sopenharmony_ci	__le32 feature_compat;
5962306a36Sopenharmony_ci	__u8 blkszbits;         /* filesystem block size in bit shift */
6062306a36Sopenharmony_ci	__u8 sb_extslots;	/* superblock size = 128 + sb_extslots * 16 */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	__le16 root_nid;	/* nid of root directory */
6362306a36Sopenharmony_ci	__le64 inos;            /* total valid ino # (== f_files - f_favail) */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	__le64 build_time;      /* compact inode time derivation */
6662306a36Sopenharmony_ci	__le32 build_time_nsec;	/* compact inode time derivation in ns scale */
6762306a36Sopenharmony_ci	__le32 blocks;          /* used for statfs */
6862306a36Sopenharmony_ci	__le32 meta_blkaddr;	/* start block address of metadata area */
6962306a36Sopenharmony_ci	__le32 xattr_blkaddr;	/* start block address of shared xattr area */
7062306a36Sopenharmony_ci	__u8 uuid[16];          /* 128-bit uuid for volume */
7162306a36Sopenharmony_ci	__u8 volume_name[16];   /* volume name */
7262306a36Sopenharmony_ci	__le32 feature_incompat;
7362306a36Sopenharmony_ci	union {
7462306a36Sopenharmony_ci		/* bitmap for available compression algorithms */
7562306a36Sopenharmony_ci		__le16 available_compr_algs;
7662306a36Sopenharmony_ci		/* customized sliding window size instead of 64k by default */
7762306a36Sopenharmony_ci		__le16 lz4_max_distance;
7862306a36Sopenharmony_ci	} __packed u1;
7962306a36Sopenharmony_ci	__le16 extra_devices;	/* # of devices besides the primary device */
8062306a36Sopenharmony_ci	__le16 devt_slotoff;	/* startoff = devt_slotoff * devt_slotsize */
8162306a36Sopenharmony_ci	__u8 dirblkbits;	/* directory block size in bit shift */
8262306a36Sopenharmony_ci	__u8 xattr_prefix_count;	/* # of long xattr name prefixes */
8362306a36Sopenharmony_ci	__le32 xattr_prefix_start;	/* start of long xattr prefixes */
8462306a36Sopenharmony_ci	__le64 packed_nid;	/* nid of the special packed inode */
8562306a36Sopenharmony_ci	__u8 xattr_filter_reserved; /* reserved for xattr name filter */
8662306a36Sopenharmony_ci	__u8 reserved2[23];
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * EROFS inode datalayout (i_format in on-disk inode):
9162306a36Sopenharmony_ci * 0 - uncompressed flat inode without tail-packing inline data:
9262306a36Sopenharmony_ci * 1 - compressed inode with non-compact indexes:
9362306a36Sopenharmony_ci * 2 - uncompressed flat inode with tail-packing inline data:
9462306a36Sopenharmony_ci * 3 - compressed inode with compact indexes:
9562306a36Sopenharmony_ci * 4 - chunk-based inode with (optional) multi-device support:
9662306a36Sopenharmony_ci * 5~7 - reserved
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_cienum {
9962306a36Sopenharmony_ci	EROFS_INODE_FLAT_PLAIN			= 0,
10062306a36Sopenharmony_ci	EROFS_INODE_COMPRESSED_FULL		= 1,
10162306a36Sopenharmony_ci	EROFS_INODE_FLAT_INLINE			= 2,
10262306a36Sopenharmony_ci	EROFS_INODE_COMPRESSED_COMPACT		= 3,
10362306a36Sopenharmony_ci	EROFS_INODE_CHUNK_BASED			= 4,
10462306a36Sopenharmony_ci	EROFS_INODE_DATALAYOUT_MAX
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic inline bool erofs_inode_is_data_compressed(unsigned int datamode)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	return datamode == EROFS_INODE_COMPRESSED_COMPACT ||
11062306a36Sopenharmony_ci		datamode == EROFS_INODE_COMPRESSED_FULL;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* bit definitions of inode i_format */
11462306a36Sopenharmony_ci#define EROFS_I_VERSION_MASK            0x01
11562306a36Sopenharmony_ci#define EROFS_I_DATALAYOUT_MASK         0x07
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define EROFS_I_VERSION_BIT             0
11862306a36Sopenharmony_ci#define EROFS_I_DATALAYOUT_BIT          1
11962306a36Sopenharmony_ci#define EROFS_I_ALL_BIT			4
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define EROFS_I_ALL	((1 << EROFS_I_ALL_BIT) - 1)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* indicate chunk blkbits, thus 'chunksize = blocksize << chunk blkbits' */
12462306a36Sopenharmony_ci#define EROFS_CHUNK_FORMAT_BLKBITS_MASK		0x001F
12562306a36Sopenharmony_ci/* with chunk indexes or just a 4-byte blkaddr array */
12662306a36Sopenharmony_ci#define EROFS_CHUNK_FORMAT_INDEXES		0x0020
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define EROFS_CHUNK_FORMAT_ALL	\
12962306a36Sopenharmony_ci	(EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES)
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* 32-byte on-disk inode */
13262306a36Sopenharmony_ci#define EROFS_INODE_LAYOUT_COMPACT	0
13362306a36Sopenharmony_ci/* 64-byte on-disk inode */
13462306a36Sopenharmony_ci#define EROFS_INODE_LAYOUT_EXTENDED	1
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistruct erofs_inode_chunk_info {
13762306a36Sopenharmony_ci	__le16 format;		/* chunk blkbits, etc. */
13862306a36Sopenharmony_ci	__le16 reserved;
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciunion erofs_inode_i_u {
14262306a36Sopenharmony_ci	/* total compressed blocks for compressed inodes */
14362306a36Sopenharmony_ci	__le32 compressed_blocks;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* block address for uncompressed flat inodes */
14662306a36Sopenharmony_ci	__le32 raw_blkaddr;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* for device files, used to indicate old/new device # */
14962306a36Sopenharmony_ci	__le32 rdev;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* for chunk-based files, it contains the summary info */
15262306a36Sopenharmony_ci	struct erofs_inode_chunk_info c;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* 32-byte reduced form of an ondisk inode */
15662306a36Sopenharmony_cistruct erofs_inode_compact {
15762306a36Sopenharmony_ci	__le16 i_format;	/* inode format hints */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
16062306a36Sopenharmony_ci	__le16 i_xattr_icount;
16162306a36Sopenharmony_ci	__le16 i_mode;
16262306a36Sopenharmony_ci	__le16 i_nlink;
16362306a36Sopenharmony_ci	__le32 i_size;
16462306a36Sopenharmony_ci	__le32 i_reserved;
16562306a36Sopenharmony_ci	union erofs_inode_i_u i_u;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	__le32 i_ino;		/* only used for 32-bit stat compatibility */
16862306a36Sopenharmony_ci	__le16 i_uid;
16962306a36Sopenharmony_ci	__le16 i_gid;
17062306a36Sopenharmony_ci	__le32 i_reserved2;
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* 64-byte complete form of an ondisk inode */
17462306a36Sopenharmony_cistruct erofs_inode_extended {
17562306a36Sopenharmony_ci	__le16 i_format;	/* inode format hints */
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
17862306a36Sopenharmony_ci	__le16 i_xattr_icount;
17962306a36Sopenharmony_ci	__le16 i_mode;
18062306a36Sopenharmony_ci	__le16 i_reserved;
18162306a36Sopenharmony_ci	__le64 i_size;
18262306a36Sopenharmony_ci	union erofs_inode_i_u i_u;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	__le32 i_ino;		/* only used for 32-bit stat compatibility */
18562306a36Sopenharmony_ci	__le32 i_uid;
18662306a36Sopenharmony_ci	__le32 i_gid;
18762306a36Sopenharmony_ci	__le64 i_mtime;
18862306a36Sopenharmony_ci	__le32 i_mtime_nsec;
18962306a36Sopenharmony_ci	__le32 i_nlink;
19062306a36Sopenharmony_ci	__u8   i_reserved2[16];
19162306a36Sopenharmony_ci};
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/*
19462306a36Sopenharmony_ci * inline xattrs (n == i_xattr_icount):
19562306a36Sopenharmony_ci * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes
19662306a36Sopenharmony_ci *          12 bytes           /                   \
19762306a36Sopenharmony_ci *                            /                     \
19862306a36Sopenharmony_ci *                           /-----------------------\
19962306a36Sopenharmony_ci *                           |  erofs_xattr_entries+ |
20062306a36Sopenharmony_ci *                           +-----------------------+
20162306a36Sopenharmony_ci * inline xattrs must starts in erofs_xattr_ibody_header,
20262306a36Sopenharmony_ci * for read-only fs, no need to introduce h_refcount
20362306a36Sopenharmony_ci */
20462306a36Sopenharmony_cistruct erofs_xattr_ibody_header {
20562306a36Sopenharmony_ci	__le32 h_name_filter;		/* bit value 1 indicates not-present */
20662306a36Sopenharmony_ci	__u8   h_shared_count;
20762306a36Sopenharmony_ci	__u8   h_reserved2[7];
20862306a36Sopenharmony_ci	__le32 h_shared_xattrs[];       /* shared xattr id array */
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/* Name indexes */
21262306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_USER              1
21362306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_POSIX_ACL_ACCESS  2
21462306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
21562306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_TRUSTED           4
21662306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_LUSTRE            5
21762306a36Sopenharmony_ci#define EROFS_XATTR_INDEX_SECURITY          6
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/*
22062306a36Sopenharmony_ci * bit 7 of e_name_index is set when it refers to a long xattr name prefix,
22162306a36Sopenharmony_ci * while the remained lower bits represent the index of the prefix.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_ci#define EROFS_XATTR_LONG_PREFIX		0x80
22462306a36Sopenharmony_ci#define EROFS_XATTR_LONG_PREFIX_MASK	0x7f
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci#define EROFS_XATTR_FILTER_BITS		32
22762306a36Sopenharmony_ci#define EROFS_XATTR_FILTER_DEFAULT	UINT32_MAX
22862306a36Sopenharmony_ci#define EROFS_XATTR_FILTER_SEED		0x25BBE08F
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/* xattr entry (for both inline & shared xattrs) */
23162306a36Sopenharmony_cistruct erofs_xattr_entry {
23262306a36Sopenharmony_ci	__u8   e_name_len;      /* length of name */
23362306a36Sopenharmony_ci	__u8   e_name_index;    /* attribute name index */
23462306a36Sopenharmony_ci	__le16 e_value_size;    /* size of attribute value */
23562306a36Sopenharmony_ci	/* followed by e_name and e_value */
23662306a36Sopenharmony_ci	char   e_name[];        /* attribute name */
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/* long xattr name prefix */
24062306a36Sopenharmony_cistruct erofs_xattr_long_prefix {
24162306a36Sopenharmony_ci	__u8   base_index;	/* short xattr name prefix index */
24262306a36Sopenharmony_ci	char   infix[];		/* infix apart from short prefix */
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	if (!i_xattr_icount)
24862306a36Sopenharmony_ci		return 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return sizeof(struct erofs_xattr_ibody_header) +
25162306a36Sopenharmony_ci		sizeof(__u32) * (le16_to_cpu(i_xattr_icount) - 1);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#define EROFS_XATTR_ALIGN(size) round_up(size, sizeof(struct erofs_xattr_entry))
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline unsigned int erofs_xattr_entry_size(struct erofs_xattr_entry *e)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return EROFS_XATTR_ALIGN(sizeof(struct erofs_xattr_entry) +
25962306a36Sopenharmony_ci				 e->e_name_len + le16_to_cpu(e->e_value_size));
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* represent a zeroed chunk (hole) */
26362306a36Sopenharmony_ci#define EROFS_NULL_ADDR			-1
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/* 4-byte block address array */
26662306a36Sopenharmony_ci#define EROFS_BLOCK_MAP_ENTRY_SIZE	sizeof(__le32)
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* 8-byte inode chunk indexes */
26962306a36Sopenharmony_cistruct erofs_inode_chunk_index {
27062306a36Sopenharmony_ci	__le16 advise;		/* always 0, don't care for now */
27162306a36Sopenharmony_ci	__le16 device_id;	/* back-end storage id (with bits masked) */
27262306a36Sopenharmony_ci	__le32 blkaddr;		/* start block address of this inode chunk */
27362306a36Sopenharmony_ci};
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/* dirent sorts in alphabet order, thus we can do binary search */
27662306a36Sopenharmony_cistruct erofs_dirent {
27762306a36Sopenharmony_ci	__le64 nid;     /* node number */
27862306a36Sopenharmony_ci	__le16 nameoff; /* start offset of file name */
27962306a36Sopenharmony_ci	__u8 file_type; /* file type */
28062306a36Sopenharmony_ci	__u8 reserved;  /* reserved */
28162306a36Sopenharmony_ci} __packed;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/*
28462306a36Sopenharmony_ci * EROFS file types should match generic FT_* types and
28562306a36Sopenharmony_ci * it seems no need to add BUILD_BUG_ONs since potential
28662306a36Sopenharmony_ci * unmatchness will break other fses as well...
28762306a36Sopenharmony_ci */
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci#define EROFS_NAME_LEN      255
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* maximum supported size of a physical compression cluster */
29262306a36Sopenharmony_ci#define Z_EROFS_PCLUSTER_MAX_SIZE	(1024 * 1024)
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/* available compression algorithm types (for h_algorithmtype) */
29562306a36Sopenharmony_cienum {
29662306a36Sopenharmony_ci	Z_EROFS_COMPRESSION_LZ4		= 0,
29762306a36Sopenharmony_ci	Z_EROFS_COMPRESSION_LZMA	= 1,
29862306a36Sopenharmony_ci	Z_EROFS_COMPRESSION_DEFLATE	= 2,
29962306a36Sopenharmony_ci	Z_EROFS_COMPRESSION_MAX
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci#define Z_EROFS_ALL_COMPR_ALGS		((1 << Z_EROFS_COMPRESSION_MAX) - 1)
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/* 14 bytes (+ length field = 16 bytes) */
30462306a36Sopenharmony_cistruct z_erofs_lz4_cfgs {
30562306a36Sopenharmony_ci	__le16 max_distance;
30662306a36Sopenharmony_ci	__le16 max_pclusterblks;
30762306a36Sopenharmony_ci	u8 reserved[10];
30862306a36Sopenharmony_ci} __packed;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/* 14 bytes (+ length field = 16 bytes) */
31162306a36Sopenharmony_cistruct z_erofs_lzma_cfgs {
31262306a36Sopenharmony_ci	__le32 dict_size;
31362306a36Sopenharmony_ci	__le16 format;
31462306a36Sopenharmony_ci	u8 reserved[8];
31562306a36Sopenharmony_ci} __packed;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci#define Z_EROFS_LZMA_MAX_DICT_SIZE	(8 * Z_EROFS_PCLUSTER_MAX_SIZE)
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/* 6 bytes (+ length field = 8 bytes) */
32062306a36Sopenharmony_cistruct z_erofs_deflate_cfgs {
32162306a36Sopenharmony_ci	u8 windowbits;			/* 8..15 for DEFLATE */
32262306a36Sopenharmony_ci	u8 reserved[5];
32362306a36Sopenharmony_ci} __packed;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/*
32662306a36Sopenharmony_ci * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
32762306a36Sopenharmony_ci *  e.g. for 4k logical cluster size,      4B        if compacted 2B is off;
32862306a36Sopenharmony_ci *                                  (4B) + 2B + (4B) if compacted 2B is on.
32962306a36Sopenharmony_ci * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
33062306a36Sopenharmony_ci * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
33162306a36Sopenharmony_ci * bit 3 : tailpacking inline pcluster (0 - off; 1 - on)
33262306a36Sopenharmony_ci * bit 4 : interlaced plain pcluster (0 - off; 1 - on)
33362306a36Sopenharmony_ci * bit 5 : fragment pcluster (0 - off; 1 - on)
33462306a36Sopenharmony_ci */
33562306a36Sopenharmony_ci#define Z_EROFS_ADVISE_COMPACTED_2B		0x0001
33662306a36Sopenharmony_ci#define Z_EROFS_ADVISE_BIG_PCLUSTER_1		0x0002
33762306a36Sopenharmony_ci#define Z_EROFS_ADVISE_BIG_PCLUSTER_2		0x0004
33862306a36Sopenharmony_ci#define Z_EROFS_ADVISE_INLINE_PCLUSTER		0x0008
33962306a36Sopenharmony_ci#define Z_EROFS_ADVISE_INTERLACED_PCLUSTER	0x0010
34062306a36Sopenharmony_ci#define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER	0x0020
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci#define Z_EROFS_FRAGMENT_INODE_BIT              7
34362306a36Sopenharmony_cistruct z_erofs_map_header {
34462306a36Sopenharmony_ci	union {
34562306a36Sopenharmony_ci		/* fragment data offset in the packed inode */
34662306a36Sopenharmony_ci		__le32  h_fragmentoff;
34762306a36Sopenharmony_ci		struct {
34862306a36Sopenharmony_ci			__le16  h_reserved1;
34962306a36Sopenharmony_ci			/* indicates the encoded size of tailpacking data */
35062306a36Sopenharmony_ci			__le16  h_idata_size;
35162306a36Sopenharmony_ci		};
35262306a36Sopenharmony_ci	};
35362306a36Sopenharmony_ci	__le16	h_advise;
35462306a36Sopenharmony_ci	/*
35562306a36Sopenharmony_ci	 * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
35662306a36Sopenharmony_ci	 * bit 4-7 : algorithm type of head 2 (logical cluster type 11).
35762306a36Sopenharmony_ci	 */
35862306a36Sopenharmony_ci	__u8	h_algorithmtype;
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
36162306a36Sopenharmony_ci	 * bit 3-6 : reserved;
36262306a36Sopenharmony_ci	 * bit 7   : move the whole file into packed inode or not.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	__u8	h_clusterbits;
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/*
36862306a36Sopenharmony_ci * On-disk logical cluster type:
36962306a36Sopenharmony_ci *    0   - literal (uncompressed) lcluster
37062306a36Sopenharmony_ci *    1,3 - compressed lcluster (for HEAD lclusters)
37162306a36Sopenharmony_ci *    2   - compressed lcluster (for NONHEAD lclusters)
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * In detail,
37462306a36Sopenharmony_ci *    0 - literal (uncompressed) lcluster,
37562306a36Sopenharmony_ci *        di_advise = 0
37662306a36Sopenharmony_ci *        di_clusterofs = the literal data offset of the lcluster
37762306a36Sopenharmony_ci *        di_blkaddr = the blkaddr of the literal pcluster
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci *    1,3 - compressed lcluster (for HEAD lclusters)
38062306a36Sopenharmony_ci *        di_advise = 1 or 3
38162306a36Sopenharmony_ci *        di_clusterofs = the decompressed data offset of the lcluster
38262306a36Sopenharmony_ci *        di_blkaddr = the blkaddr of the compressed pcluster
38362306a36Sopenharmony_ci *
38462306a36Sopenharmony_ci *    2 - compressed lcluster (for NONHEAD lclusters)
38562306a36Sopenharmony_ci *        di_advise = 2
38662306a36Sopenharmony_ci *        di_clusterofs =
38762306a36Sopenharmony_ci *           the decompressed data offset in its own HEAD lcluster
38862306a36Sopenharmony_ci *        di_u.delta[0] = distance to this HEAD lcluster
38962306a36Sopenharmony_ci *        di_u.delta[1] = distance to the next HEAD lcluster
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_cienum {
39262306a36Sopenharmony_ci	Z_EROFS_LCLUSTER_TYPE_PLAIN	= 0,
39362306a36Sopenharmony_ci	Z_EROFS_LCLUSTER_TYPE_HEAD1	= 1,
39462306a36Sopenharmony_ci	Z_EROFS_LCLUSTER_TYPE_NONHEAD	= 2,
39562306a36Sopenharmony_ci	Z_EROFS_LCLUSTER_TYPE_HEAD2	= 3,
39662306a36Sopenharmony_ci	Z_EROFS_LCLUSTER_TYPE_MAX
39762306a36Sopenharmony_ci};
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci#define Z_EROFS_LI_LCLUSTER_TYPE_BITS        2
40062306a36Sopenharmony_ci#define Z_EROFS_LI_LCLUSTER_TYPE_BIT         0
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci/* (noncompact only, HEAD) This pcluster refers to partial decompressed data */
40362306a36Sopenharmony_ci#define Z_EROFS_LI_PARTIAL_REF		(1 << 15)
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci/*
40662306a36Sopenharmony_ci * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
40762306a36Sopenharmony_ci * compressed block count of a compressed extent (in logical clusters, aka.
40862306a36Sopenharmony_ci * block count of a pcluster).
40962306a36Sopenharmony_ci */
41062306a36Sopenharmony_ci#define Z_EROFS_LI_D0_CBLKCNT		(1 << 11)
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistruct z_erofs_lcluster_index {
41362306a36Sopenharmony_ci	__le16 di_advise;
41462306a36Sopenharmony_ci	/* where to decompress in the head lcluster */
41562306a36Sopenharmony_ci	__le16 di_clusterofs;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	union {
41862306a36Sopenharmony_ci		/* for the HEAD lclusters */
41962306a36Sopenharmony_ci		__le32 blkaddr;
42062306a36Sopenharmony_ci		/*
42162306a36Sopenharmony_ci		 * for the NONHEAD lclusters
42262306a36Sopenharmony_ci		 * [0] - distance to its HEAD lcluster
42362306a36Sopenharmony_ci		 * [1] - distance to the next HEAD lcluster
42462306a36Sopenharmony_ci		 */
42562306a36Sopenharmony_ci		__le16 delta[2];
42662306a36Sopenharmony_ci	} di_u;
42762306a36Sopenharmony_ci};
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci#define Z_EROFS_FULL_INDEX_ALIGN(end)	\
43062306a36Sopenharmony_ci	(ALIGN(end, 8) + sizeof(struct z_erofs_map_header) + 8)
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/* check the EROFS on-disk layout strictly at compile time */
43362306a36Sopenharmony_cistatic inline void erofs_check_ondisk_layout_definitions(void)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	const __le64 fmh = *(__le64 *)&(struct z_erofs_map_header) {
43662306a36Sopenharmony_ci		.h_clusterbits = 1 << Z_EROFS_FRAGMENT_INODE_BIT
43762306a36Sopenharmony_ci	};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
44062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_inode_compact) != 32);
44162306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_inode_extended) != 64);
44262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
44362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
44462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_info) != 4);
44562306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) != 8);
44662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
44762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct z_erofs_lcluster_index) != 8);
44862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
44962306a36Sopenharmony_ci	/* keep in sync between 2 index structures for better extendibility */
45062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) !=
45162306a36Sopenharmony_ci		     sizeof(struct z_erofs_lcluster_index));
45262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erofs_deviceslot) != 128);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	BUILD_BUG_ON(BIT(Z_EROFS_LI_LCLUSTER_TYPE_BITS) <
45562306a36Sopenharmony_ci		     Z_EROFS_LCLUSTER_TYPE_MAX - 1);
45662306a36Sopenharmony_ci	/* exclude old compiler versions like gcc 7.5.0 */
45762306a36Sopenharmony_ci	BUILD_BUG_ON(__builtin_constant_p(fmh) ?
45862306a36Sopenharmony_ci		     fmh != cpu_to_le64(1ULL << 63) : 0);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci#endif
462