]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - fs/erofs/erofs_fs.h
fs/erofs: Introduce new features including ztailpacking, fragments and dedupe
[thirdparty/u-boot.git] / fs / erofs / erofs_fs.h
index 6b62c7a4f5f569da8a4111a4ca92244ed7dea22c..158e2c68a1a6d1cde7f80f3f8523683fba16885b 100644 (file)
@@ -3,7 +3,7 @@
  * EROFS (Enhanced ROM File System) on-disk format definition
  *
  * Copyright (C) 2017-2018 HUAWEI, Inc.
- *             http://www.huawei.com/
+ *             https://www.huawei.com/
  * Copyright (C) 2021, Alibaba Cloud
  */
 #ifndef __EROFS_FS_H
 #define EROFS_SUPER_MAGIC_V1    0xE0F5E1E2
 #define EROFS_SUPER_OFFSET      1024
 
-#define EROFS_FEATURE_COMPAT_SB_CHKSUM         0x00000001
+#define EROFS_FEATURE_COMPAT_SB_CHKSUM          0x00000001
+#define EROFS_FEATURE_COMPAT_MTIME              0x00000002
 
 /*
  * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
  * be incompatible with this kernel version.
  */
-#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING    0x00000001
+#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_LZ4_0PADDING | \
+       (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_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 {
-       union {
-               u8 uuid[16];            /* used for device manager later */
-               u8 userdata[64];        /* digest(sha256), etc. */
-       } u;
-       __le32 blocks;                  /* total fs blocks of this device */
-       __le32 mapped_blkaddr;          /* map starting at mapped_blkaddr */
+       u8 tag[64];             /* digest(sha256), etc. */
+       __le32 blocks;          /* total fs blocks of this device */
+       __le32 mapped_blkaddr;  /* map starting at mapped_blkaddr */
        u8 reserved[56];
 };
 
@@ -55,14 +63,14 @@ struct erofs_super_block {
        __le32 magic;           /* file system magic number */
        __le32 checksum;        /* crc32c(super_block) */
        __le32 feature_compat;
-       __u8 blkszbits;         /* support block_size == PAGE_SIZE only */
+       __u8 blkszbits;         /* filesystem block size in bit shift */
        __u8 sb_extslots;       /* superblock size = 128 + sb_extslots * 16 */
 
        __le16 root_nid;        /* nid of root directory */
        __le64 inos;            /* total valid ino # (== f_files - f_favail) */
 
-       __le64 build_time;      /* inode v1 time derivation */
-       __le32 build_time_nsec; /* inode v1 time derivation in nano scale */
+       __le64 build_time;      /* compact inode time derivation */
+       __le32 build_time_nsec; /* compact inode time derivation in ns scale */
        __le32 blocks;          /* used for statfs */
        __le32 meta_blkaddr;    /* start block address of metadata area */
        __le32 xattr_blkaddr;   /* start block address of shared xattr area */
@@ -77,39 +85,38 @@ struct erofs_super_block {
        } __packed u1;
        __le16 extra_devices;   /* # of devices besides the primary device */
        __le16 devt_slotoff;    /* startoff = devt_slotoff * devt_slotsize */
-       __u8 reserved2[38];
+       __u8 dirblkbits;        /* directory block size in bit shift */
+       __u8 xattr_prefix_count;        /* # of long xattr name prefixes */
+       __le32 xattr_prefix_start;      /* start of long xattr prefixes */
+       __le64 packed_nid;      /* nid of the special packed inode */
+       __u8 reserved2[24];
 };
 
 /*
- * erofs inode datalayout (i_format in on-disk inode):
- * 0 - inode plain without inline data A:
- * inode, [xattrs], ... | ... | no-holed data
- * 1 - inode VLE compression B (legacy):
- * inode, [xattrs], extents ... | ...
- * 2 - inode plain with inline data C:
- * inode, [xattrs], last_inline_data, ... | ... | no-holed data
- * 3 - inode compression D:
- * inode, [xattrs], map_header, extents ... | ...
- * 4 - inode chunk-based E:
- * inode, [xattrs], chunk indexes ... | ...
+ * EROFS inode datalayout (i_format in on-disk inode):
+ * 0 - uncompressed flat inode without tail-packing inline data:
+ * 1 - compressed inode with non-compact indexes:
+ * 2 - uncompressed flat inode with tail-packing inline data:
+ * 3 - compressed inode with compact indexes:
+ * 4 - chunk-based inode with (optional) multi-device support:
  * 5~7 - reserved
  */
 enum {
        EROFS_INODE_FLAT_PLAIN                  = 0,
-       EROFS_INODE_FLAT_COMPRESSION_LEGACY     = 1,
+       EROFS_INODE_COMPRESSED_FULL             = 1,
        EROFS_INODE_FLAT_INLINE                 = 2,
-       EROFS_INODE_FLAT_COMPRESSION            = 3,
+       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_FLAT_COMPRESSION ||
-               datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
+       return datamode == EROFS_INODE_COMPRESSED_COMPACT ||
+               datamode == EROFS_INODE_COMPRESSED_FULL;
 }
 
-/* bit definitions of inode i_advise */
+/* bit definitions of inode i_format */
 #define EROFS_I_VERSION_BITS            1
 #define EROFS_I_DATALAYOUT_BITS         3
 
@@ -127,11 +134,30 @@ static inline bool erofs_inode_is_data_compressed(unsigned int datamode)
 #define EROFS_CHUNK_FORMAT_ALL \
        (EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES)
 
+/* 32-byte on-disk inode */
+#define EROFS_INODE_LAYOUT_COMPACT     0
+/* 64-byte on-disk inode */
+#define EROFS_INODE_LAYOUT_EXTENDED    1
+
 struct erofs_inode_chunk_info {
        __le16 format;          /* chunk blkbits, etc. */
        __le16 reserved;
 };
 
+union erofs_inode_i_u {
+       /* total compressed blocks for compressed inodes */
+       __le32 compressed_blocks;
+
+       /* block address for uncompressed flat inodes */
+       __le32 raw_blkaddr;
+
+       /* for device files, used to indicate old/new device # */
+       __le32 rdev;
+
+       /* for chunk-based files, it contains the summary info */
+       struct erofs_inode_chunk_info c;
+};
+
 /* 32-byte reduced form of an ondisk inode */
 struct erofs_inode_compact {
        __le16 i_format;        /* inode format hints */
@@ -142,28 +168,14 @@ struct erofs_inode_compact {
        __le16 i_nlink;
        __le32 i_size;
        __le32 i_reserved;
-       union {
-               /* file total compressed blocks for data mapping 1 */
-               __le32 compressed_blocks;
-               __le32 raw_blkaddr;
+       union erofs_inode_i_u i_u;
 
-               /* for device files, used to indicate old/new device # */
-               __le32 rdev;
-
-               /* for chunk-based files, it contains the summary info */
-               struct erofs_inode_chunk_info c;
-       } i_u;
-       __le32 i_ino;           /* only used for 32-bit stat compatibility */
+       __le32 i_ino;           /* only used for 32-bit stat compatibility */
        __le16 i_uid;
        __le16 i_gid;
        __le32 i_reserved2;
 };
 
-/* 32 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_COMPACT     0
-/* 64 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_EXTENDED    1
-
 /* 64-byte complete form of an ondisk inode */
 struct erofs_inode_extended {
        __le16 i_format;        /* inode format hints */
@@ -173,33 +185,17 @@ struct erofs_inode_extended {
        __le16 i_mode;
        __le16 i_reserved;
        __le64 i_size;
-       union {
-               /* file total compressed blocks for data mapping 1 */
-               __le32 compressed_blocks;
-               __le32 raw_blkaddr;
-
-               /* for device files, used to indicate old/new device # */
-               __le32 rdev;
-
-               /* for chunk-based files, it contains the summary info */
-               struct erofs_inode_chunk_info c;
-       } i_u;
-
-       /* only used for 32-bit stat compatibility */
-       __le32 i_ino;
+       union erofs_inode_i_u i_u;
 
+       __le32 i_ino;           /* only used for 32-bit stat compatibility */
        __le32 i_uid;
        __le32 i_gid;
-       __le64 i_ctime;
-       __le32 i_ctime_nsec;
+       __le64 i_mtime;
+       __le32 i_mtime_nsec;
        __le32 i_nlink;
        __u8   i_reserved2[16];
 };
 
-#define EROFS_MAX_SHARED_XATTRS         (128)
-/* h_shared_count between 129 ... 255 are special # */
-#define EROFS_SHARED_XATTR_EXTENT       (255)
-
 /*
  * inline xattrs (n == i_xattr_icount):
  * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes
@@ -226,6 +222,13 @@ struct erofs_xattr_ibody_header {
 #define EROFS_XATTR_INDEX_LUSTRE            5
 #define EROFS_XATTR_INDEX_SECURITY          6
 
+/*
+ * bit 7 of e_name_index is set when it refers to a long xattr name prefix,
+ * while the remained lower bits represent the index of the prefix.
+ */
+#define EROFS_XATTR_LONG_PREFIX                0x80
+#define EROFS_XATTR_LONG_PREFIX_MASK   0x7f
+
 /* xattr entry (for both inline & shared xattrs) */
 struct erofs_xattr_entry {
        __u8   e_name_len;      /* length of name */
@@ -235,6 +238,12 @@ struct erofs_xattr_entry {
        char   e_name[0];       /* attribute name */
 };
 
+/* long xattr name prefix */
+struct erofs_xattr_long_prefix {
+       __u8   base_index;      /* short xattr name prefix index */
+       char   infix[0];        /* infix apart from short prefix */
+};
+
 static inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount)
 {
        if (!i_xattr_icount)
@@ -265,6 +274,29 @@ struct erofs_inode_chunk_index {
        __le32 blkaddr;         /* start block address of this inode chunk */
 };
 
+/* dirent sorts in alphabet order, thus we can do binary search */
+struct erofs_dirent {
+       __le64 nid;     /* node number */
+       __le16 nameoff; /* start offset of file name */
+       __u8 file_type; /* file type */
+       __u8 reserved;  /* reserved */
+} __packed;
+
+/* file types used in inode_info->flags */
+enum {
+       EROFS_FT_UNKNOWN,
+       EROFS_FT_REG_FILE,
+       EROFS_FT_DIR,
+       EROFS_FT_CHRDEV,
+       EROFS_FT_BLKDEV,
+       EROFS_FT_FIFO,
+       EROFS_FT_SOCK,
+       EROFS_FT_SYMLINK,
+       EROFS_FT_MAX
+};
+
+#define EROFS_NAME_LEN      255
+
 /* maximum supported size of a physical compression cluster */
 #define Z_EROFS_PCLUSTER_MAX_SIZE      (1024 * 1024)
 
@@ -275,7 +307,7 @@ enum {
        Z_EROFS_COMPRESSION_MAX
 };
 
-#define Z_EROFS_ALL_COMPR_ALGS         (1 << (Z_EROFS_COMPRESSION_MAX - 1))
+#define Z_EROFS_ALL_COMPR_ALGS         ((1 << Z_EROFS_COMPRESSION_MAX) - 1)
 
 /* 14 bytes (+ length field = 16 bytes) */
 struct z_erofs_lz4_cfgs {
@@ -290,6 +322,7 @@ struct z_erofs_lzma_cfgs {
        __le16 format;
        u8 reserved[8];
 } __packed;
+
 #define Z_EROFS_LZMA_MAX_DICT_SIZE     (8 * Z_EROFS_PCLUSTER_MAX_SIZE)
 
 /*
@@ -298,13 +331,28 @@ struct z_erofs_lzma_cfgs {
  *                                  (4B) + 2B + (4B) if compacted 2B is on.
  * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
  * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
+ * bit 3 : tailpacking inline pcluster (0 - off; 1 - on)
+ * bit 4 : interlaced plain pcluster (0 - off; 1 - on)
+ * bit 5 : fragment pcluster (0 - off; 1 - on)
  */
 #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 {
-       __le32  h_reserved1;
+       union {
+               /* fragment data offset in the packed inode */
+               __le32  h_fragmentoff;
+               struct {
+                       __le16  h_reserved1;
+                       /* indicates the encoded size of tailpacking data */
+                       __le16  h_idata_size;
+               };
+       };
        __le16  h_advise;
        /*
         * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
@@ -313,107 +361,85 @@ struct z_erofs_map_header {
        __u8    h_algorithmtype;
        /*
         * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
-        * bit 3-7 : reserved.
+        * bit 3-6 : reserved;
+        * bit 7   : move the whole file into packed inode or not.
         */
        __u8    h_clusterbits;
 };
 
-#define Z_EROFS_VLE_LEGACY_HEADER_PADDING       8
-
 /*
- * Fixed-sized output compression ondisk Logical Extent cluster type:
- *    0 - literal (uncompressed) cluster
- *    1 - compressed cluster (for the head logical cluster)
- *    2 - compressed cluster (for the other logical clusters)
+ * On-disk logical cluster type:
+ *    0   - literal (uncompressed) lcluster
+ *    1,3 - compressed lcluster (for HEAD lclusters)
+ *    2   - compressed lcluster (for NONHEAD lclusters)
  *
  * In detail,
- *    0 - literal (uncompressed) cluster,
+ *    0 - literal (uncompressed) lcluster,
  *        di_advise = 0
- *        di_clusterofs = the literal data offset of the cluster
- *        di_blkaddr = the blkaddr of the literal cluster
+ *        di_clusterofs = the literal data offset of the lcluster
+ *        di_blkaddr = the blkaddr of the literal pcluster
  *
- *    1 - compressed cluster (for the head logical cluster)
- *        di_advise = 1
- *        di_clusterofs = the decompressed data offset of the cluster
- *        di_blkaddr = the blkaddr of the compressed cluster
+ *    1,3 - compressed lcluster (for HEAD lclusters)
+ *        di_advise = 1 or 3
+ *        di_clusterofs = the decompressed data offset of the lcluster
+ *        di_blkaddr = the blkaddr of the compressed pcluster
  *
- *    2 - compressed cluster (for the other logical clusters)
+ *    2 - compressed lcluster (for NONHEAD lclusters)
  *        di_advise = 2
  *        di_clusterofs =
- *           the decompressed data offset in its own head cluster
- *        di_u.delta[0] = distance to its corresponding head cluster
- *        di_u.delta[1] = distance to its corresponding tail cluster
- *                (di_advise could be 0, 1 or 2)
+ *           the decompressed data offset in its own HEAD lcluster
+ *        di_u.delta[0] = distance to this HEAD lcluster
+ *        di_u.delta[1] = distance to the next HEAD lcluster
  */
 enum {
-       Z_EROFS_VLE_CLUSTER_TYPE_PLAIN          = 0,
-       Z_EROFS_VLE_CLUSTER_TYPE_HEAD           = 1,
-       Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD        = 2,
-       Z_EROFS_VLE_CLUSTER_TYPE_RESERVED       = 3,
-       Z_EROFS_VLE_CLUSTER_TYPE_MAX
+       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_VLE_DI_CLUSTER_TYPE_BITS        2
-#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT         0
+#define Z_EROFS_LI_LCLUSTER_TYPE_BITS        2
+#define Z_EROFS_LI_LCLUSTER_TYPE_BIT         0
+
+/* (noncompact only, HEAD) This pcluster refers to partial decompressed data */
+#define Z_EROFS_LI_PARTIAL_REF         (1 << 15)
 
 /*
  * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
  * compressed block count of a compressed extent (in logical clusters, aka.
  * block count of a pcluster).
  */
-#define Z_EROFS_VLE_DI_D0_CBLKCNT              (1 << 11)
+#define Z_EROFS_LI_D0_CBLKCNT          (1 << 11)
 
-struct z_erofs_vle_decompressed_index {
+struct z_erofs_lcluster_index {
        __le16 di_advise;
-       /* where to decompress in the head cluster */
+       /* where to decompress in the head lcluster */
        __le16 di_clusterofs;
 
        union {
-               /* for the head cluster */
+               /* for the HEAD lclusters */
                __le32 blkaddr;
                /*
-                * for the rest clusters
-                * eg. for 4k page-sized cluster, maximum 4K*64k = 256M)
-                * [0] - pointing to the head cluster
-                * [1] - pointing to the tail cluster
+                * for the NONHEAD lclusters
+                * [0] - distance to its HEAD lcluster
+                * [1] - distance to the next HEAD lcluster
                 */
                __le16 delta[2];
        } di_u;
 };
 
-#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
-       (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
-        sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
-
-#define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \
-       sizeof(struct z_erofs_vle_decompressed_index))
-
-/* dirent sorts in alphabet order, thus we can do binary search */
-struct erofs_dirent {
-       __le64 nid;     /* node number */
-       __le16 nameoff; /* start offset of file name */
-       __u8 file_type; /* file type */
-       __u8 reserved;  /* reserved */
-} __packed;
-
-/* file types used in inode_info->flags */
-enum {
-       EROFS_FT_UNKNOWN,
-       EROFS_FT_REG_FILE,
-       EROFS_FT_DIR,
-       EROFS_FT_CHRDEV,
-       EROFS_FT_BLKDEV,
-       EROFS_FT_FIFO,
-       EROFS_FT_SOCK,
-       EROFS_FT_SYMLINK,
-       EROFS_FT_MAX
-};
-
-#define EROFS_NAME_LEN      255
+#define Z_EROFS_FULL_INDEX_ALIGN(end)  \
+       (round_up(end, 8) + sizeof(struct z_erofs_map_header) + 8)
 
 /* check the EROFS on-disk layout strictly at compile time */
 static inline void erofs_check_ondisk_layout_definitions(void)
 {
+       const __le64 fmh __maybe_unused =
+               *(__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);
@@ -422,15 +448,18 @@ static inline void erofs_check_ondisk_layout_definitions(void)
        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_vle_decompressed_index) != 8);
+       BUILD_BUG_ON(sizeof(struct z_erofs_lcluster_index) != 8);
        BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
        /* keep in sync between 2 index structures for better extendibility */
        BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) !=
-                    sizeof(struct z_erofs_vle_decompressed_index));
+                    sizeof(struct z_erofs_lcluster_index));
        BUILD_BUG_ON(sizeof(struct erofs_deviceslot) != 128);
 
-       BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) <
-                    Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
+       BUILD_BUG_ON(BIT(Z_EROFS_LI_LCLUSTER_TYPE_BITS) <
+                    Z_EROFS_LCLUSTER_TYPE_MAX - 1);
+       /* exclude old compiler versions like gcc 7.5.0 */
+       BUILD_BUG_ON(__builtin_constant_p(fmh) ?
+                    fmh != cpu_to_le64(1ULL << 63) : 0);
 }
 
 #endif