fs/erofs: Introduce new features including ztailpacking, fragments and dedupe
This patch updates erofs driver code to catch up with the latest code of
erofs_utils (commit e4939f9eaa177e05d697ace85d8dc283e25dc2ed).
LZMA will be supported in the separate patch later.
Signed-off-by: Yifan Zhao <zhaoyifan@sjtu.edu.cn>
Reviewed-by: Huang Jianan <jnhuang95@gmail.com>
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 4af7c91..433a3c6 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -2,6 +2,7 @@
#ifndef __EROFS_INTERNAL_H
#define __EROFS_INTERNAL_H
+#include "linux/compat.h"
#define __packed __attribute__((__packed__))
#include <linux/stat.h>
@@ -30,8 +31,9 @@
#define PAGE_MASK (~(PAGE_SIZE - 1))
-#define LOG_BLOCK_SIZE (12)
-#define EROFS_BLKSIZ (1U << LOG_BLOCK_SIZE)
+#ifndef EROFS_MAX_BLOCK_SIZE
+#define EROFS_MAX_BLOCK_SIZE PAGE_SIZE
+#endif
#define EROFS_ISLOTBITS 5
#define EROFS_SLOTSIZE (1U << EROFS_ISLOTBITS)
@@ -44,11 +46,15 @@
#define NULL_ADDR ((unsigned int)-1)
#define NULL_ADDR_UL ((unsigned long)-1)
-#define erofs_blknr(addr) ((addr) / EROFS_BLKSIZ)
-#define erofs_blkoff(addr) ((addr) % EROFS_BLKSIZ)
-#define blknr_to_addr(nr) ((erofs_off_t)(nr) * EROFS_BLKSIZ)
+/* global sbi */
+extern struct erofs_sb_info sbi;
-#define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, EROFS_BLKSIZ)
+#define erofs_blksiz() (1u << sbi.blkszbits)
+#define erofs_blknr(addr) ((addr) >> sbi.blkszbits)
+#define erofs_blkoff(addr) ((addr) & (erofs_blksiz() - 1))
+#define erofs_pos(nr) ((erofs_off_t)(nr) << sbi.blkszbits)
+
+#define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, 1u << sbi.blkszbits)
struct erofs_buffer_head;
@@ -57,6 +63,8 @@
u32 mapped_blkaddr;
};
+#define EROFS_PACKED_NID_UNALLOCATED -1
+
struct erofs_sb_info {
struct erofs_device_info *devs;
@@ -72,6 +80,7 @@
u32 build_time_nsec;
unsigned char islotbits;
+ unsigned char blkszbits;
/* what we really care is nid, rather than ino.. */
erofs_nid_t root_nid;
@@ -79,23 +88,29 @@
u64 inos;
u8 uuid[16];
+ char volume_name[16];
u16 available_compr_algs;
u16 lz4_max_distance;
+
u32 checksum;
u16 extra_devices;
union {
u16 devt_slotoff; /* used for mkfs */
u16 device_id_mask; /* used for others */
};
+ erofs_nid_t packed_nid;
+
+ u32 xattr_prefix_start;
+ u8 xattr_prefix_count;
};
-/* global sbi */
-extern struct erofs_sb_info sbi;
+/* make sure that any user of the erofs headers has at least 64bit off_t type */
+extern int erofs_assert_largefile[sizeof(off_t) - 8];
static inline erofs_off_t iloc(erofs_nid_t nid)
{
- return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits);
+ return erofs_pos(sbi.meta_blkaddr) + (nid << sbi.islotbits);
}
#define EROFS_FEATURE_FUNCS(name, compat, feature) \
@@ -112,11 +127,15 @@
sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \
}
-EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_ZERO_PADDING)
EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER)
EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE)
EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE)
+EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING)
+EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS)
+EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE)
+EROFS_FEATURE_FUNCS(xattr_prefixes, incompat, INCOMPAT_XATTR_PREFIXES)
EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
#define EROFS_I_EA_INITED (1 << 0)
@@ -130,6 +149,8 @@
unsigned int flags;
/* (mkfs.erofs) device ID containing source file */
u32 dev;
+ /* (mkfs.erofs) queued sub-directories blocking dump */
+ u32 subdirs_queued;
};
unsigned int i_count;
struct erofs_inode *i_parent;
@@ -140,8 +161,8 @@
u64 i_ino[2];
u32 i_uid;
u32 i_gid;
- u64 i_ctime;
- u32 i_ctime_nsec;
+ u64 i_mtime;
+ u32 i_mtime_nsec;
u32 i_nlink;
union {
@@ -154,20 +175,31 @@
};
} u;
+ char *i_srcpath;
+
unsigned char datalayout;
unsigned char inode_isize;
/* inline tail-end packing size */
unsigned short idata_size;
+ bool compressed_idata;
+ bool lazy_tailblock;
unsigned int xattr_isize;
unsigned int extent_isize;
+ unsigned int xattr_shared_count;
+ unsigned int *xattr_shared_xattrs;
+
erofs_nid_t nid;
struct erofs_buffer_head *bh;
struct erofs_buffer_head *bh_inline, *bh_data;
void *idata;
+ /* (ztailpacking) in order to recover uncompressed EOF data */
+ void *eof_tailraw;
+ unsigned int eof_tailrawsize;
+
union {
void *compressmeta;
void *chunkindexes;
@@ -176,8 +208,14 @@
uint8_t z_algorithmtype[2];
uint8_t z_logical_clusterbits;
uint8_t z_physical_clusterblks;
+ uint64_t z_tailextent_headlcn;
+ unsigned int z_idataoff;
+#define z_idata_size idata_size
};
};
+ uint64_t capabilities;
+ erofs_off_t fragmentoff;
+ unsigned int fragment_size;
};
static inline bool is_inode_layout_compression(struct erofs_inode *inode)
@@ -216,6 +254,14 @@
};
};
+static inline bool is_dot_dotdot_len(const char *name, unsigned int len)
+{
+ if (len >= 1 && name[0] != '.')
+ return false;
+
+ return len == 1 || (len == 2 && name[1] == '.');
+}
+
static inline bool is_dot_dotdot(const char *name)
{
if (name[0] != '.')
@@ -229,6 +275,8 @@
BH_Mapped,
BH_Encoded,
BH_FullMapped,
+ BH_Fragment,
+ BH_Partialref,
};
/* Has a disk mapping */
@@ -239,9 +287,13 @@
#define EROFS_MAP_ENCODED (1 << BH_Encoded)
/* The length of extent is full */
#define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped)
+/* Located in the special packed inode */
+#define EROFS_MAP_FRAGMENT (1 << BH_Fragment)
+/* The extent refers to partial decompressed data */
+#define EROFS_MAP_PARTIAL_REF (1 << BH_Partialref)
struct erofs_map_blocks {
- char mpage[EROFS_BLKSIZ];
+ char mpage[EROFS_MAX_BLOCK_SIZE];
erofs_off_t m_pa, m_la;
u64 m_plen, m_llen;
@@ -257,9 +309,12 @@
* approach instead if possible since it's more metadata lightweight.)
*/
#define EROFS_GET_BLOCKS_FIEMAP 0x0002
+/* Used to map tail extent for tailpacking inline or fragment pcluster */
+#define EROFS_GET_BLOCKS_FINDTAIL 0x0008
enum {
Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+ Z_EROFS_COMPRESSION_INTERLACED,
Z_EROFS_COMPRESSION_RUNTIME_MAX
};
@@ -274,6 +329,7 @@
/* super.c */
int erofs_read_superblock(void);
+void erofs_put_super(void);
/* namei.c */
int erofs_read_inode_from_disk(struct erofs_inode *vi);
@@ -283,9 +339,40 @@
/* data.c */
int erofs_pread(struct erofs_inode *inode, char *buf,
erofs_off_t count, erofs_off_t offset);
-int erofs_map_blocks(struct erofs_inode *inode,
- struct erofs_map_blocks *map, int flags);
-int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map);
+int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map,
+ int flags);
+int erofs_map_dev(struct erofs_map_dev *map);
+int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset,
+ size_t len);
+int z_erofs_read_one_data(struct erofs_inode *inode,
+ struct erofs_map_blocks *map, char *raw, char *buffer,
+ erofs_off_t skip, erofs_off_t length, bool trimmed);
+
+static inline int erofs_get_occupied_size(const struct erofs_inode *inode,
+ erofs_off_t *size)
+{
+ *size = 0;
+ switch (inode->datalayout) {
+ case EROFS_INODE_FLAT_INLINE:
+ case EROFS_INODE_FLAT_PLAIN:
+ case EROFS_INODE_CHUNK_BASED:
+ *size = inode->i_size;
+ break;
+ case EROFS_INODE_COMPRESSED_FULL:
+ case EROFS_INODE_COMPRESSED_COMPACT:
+ *size = inode->u.i_blocks * erofs_blksiz();
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/* data.c */
+int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer,
+ size_t buffer_size);
+int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size);
+
/* zmap.c */
int z_erofs_fill_inode(struct erofs_inode *vi);
int z_erofs_map_blocks_iter(struct erofs_inode *vi,