/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2017-2018 HUAWEI, Inc. * https://www.huawei.com/ * Copyright (C) 2021, Alibaba Cloud */ #ifndef __EROFS_INTERNAL_H #define __EROFS_INTERNAL_H #include #include // MUST FIRST #include #include #include #include #include #include #include #include "erofs_fs.h" MALLOC_DECLARE(M_EROFS); struct cdev; struct g_consumer; struct erofs_device_info; /* EROFS_SUPER_MAGIC_V1 to represent the whole file system */ #define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1 typedef uint64_t erofs_nid_t; typedef uint64_t erofs_off_t; typedef uint64_t erofs_blk_t; #define EROFS_MOUNT_POSIX_ACL 0x00000020 #define clear_opt(opt, option) ((opt)->mount_opt &= ~EROFS_MOUNT_##option) #define set_opt(opt, option) ((opt)->mount_opt |= EROFS_MOUNT_##option) #define test_opt(opt, option) ((opt)->mount_opt & EROFS_MOUNT_##option) struct erofs_sb_info_opts { unsigned int mount_opt; }; struct erofs_device_info { struct vnode *devvp; struct cdev *dev; struct g_consumer *cp; uint64_t mediasize; uint32_t sectorsize; erofs_blk_t blocks; erofs_blk_t uniaddr; }; struct erofs_xattr_prefix_item { uint8_t base_index; uint8_t infix_len; char *infix; }; struct erofs_map_blocks { erofs_off_t m_pa, m_la; uint64_t m_plen, m_llen; unsigned short m_deviceid; uint8_t m_algorithmformat; unsigned int m_flags; }; enum erofs_zextent_cache_state { EROFS_ZCACHE_EMPTY, EROFS_ZCACHE_INFLIGHT, EROFS_ZCACHE_READY, EROFS_ZCACHE_FAILED, }; struct erofs_zextent_cache_metrics { uint64_t hits; uint64_t misses; uint64_t bypasses; uint64_t evictions; uint64_t reclaims; size_t resident_bytes; }; struct erofs_zextent_cache { struct erofs_map_blocks map; void *data; erofs_nid_t nid; size_t decoded_size; size_t charged_bytes; size_t budget_bytes; uint64_t minimum_decode_work; struct erofs_zextent_cache_metrics metrics[Z_EROFS_COMPRESSION_MAX]; unsigned int waiters; int error; enum erofs_zextent_cache_state state; struct cv cv; bool closing; }; enum erofs_xattr_cache_state { EROFS_XATTR_CACHE_EMPTY, EROFS_XATTR_CACHE_INFLIGHT, EROFS_XATTR_CACHE_READY, EROFS_XATTR_CACHE_FAILED, }; struct erofs_xattr_cache { struct mtx lock; struct cv cv; void *data; size_t size; size_t charged_bytes; unsigned int waiters; int error; enum erofs_xattr_cache_state state; bool closing; bool initialized; }; #define EROFS_STREAM_CTX_WRAPPER_SIZE 256 struct erofs_stream_ctx; typedef int erofs_stream_ctx_init_t(struct erofs_stream_ctx *ctx); typedef void erofs_stream_ctx_fini_t(struct erofs_stream_ctx *ctx); struct erofs_stream_ctx { STAILQ_ENTRY(erofs_stream_ctx) link; struct erofs_sb_info *sbi; erofs_stream_ctx_fini_t *fini; size_t charged_bytes; uint8_t algorithm; bool cached; bool allocation_failed; }; STAILQ_HEAD(erofs_stream_ctx_head, erofs_stream_ctx); struct erofs_stream_pool_codec { struct erofs_stream_ctx_head idle; unsigned int contexts; unsigned int cached; unsigned int borrowed; unsigned int idle_count; }; struct erofs_stream_pool { struct erofs_stream_pool_codec codec[Z_EROFS_COMPRESSION_MAX]; size_t resident_bytes; struct cv cv; bool closing; }; struct erofs_sb_info { struct mount *mnt; struct erofs_device_info dif0; uint32_t block_size; uint32_t sb_size; uint8_t blkszbits; uint32_t meta_blkaddr; uint32_t xattr_blkaddr; uint32_t xattr_prefix_start; uint8_t xattr_prefix_count; uint8_t xattr_filter_reserved; erofs_nid_t packed_nid; erofs_nid_t metabox_nid; struct erofs_inode *metabox_en; struct erofs_inode *packed_inode; struct erofs_xattr_prefix_item *xattr_prefixes; erofs_blk_t blocks; uint64_t inos; erofs_nid_t root_nid; int64_t epoch; uint32_t fixed_nsec; uint32_t generation_seed; uint32_t feature_compat; uint32_t feature_incompat; char volume_name[17]; struct erofs_sb_info_opts opt; uint16_t available_compr_algs; uint32_t lzma_dict_size; uint8_t deflate_windowbits; uint8_t zstd_windowlog; /* Device table */ uint16_t extra_devices; uint16_t device_id_mask; bool flatdev; erofs_blk_t total_blocks; erofs_blk_t flatdev_blocks; struct erofs_device_info *devs; struct mtx z_extent_cache_lock; struct erofs_zextent_cache z_extent_cache; LIST_ENTRY(erofs_sb_info) z_extent_cache_link; bool z_extent_cache_initialized; struct erofs_stream_pool stream_pool; LIST_ENTRY(erofs_sb_info) stream_pool_link; bool stream_pool_initialized; volatile u_long xattr_cache_resident; }; #define MTOE(mp) ((struct erofs_sb_info *)(mp)->mnt_data) #define EROFS_FEATURE_FUNCS(name, compat, feature) \ static inline bool erofs_sb_has_##name(const struct erofs_sb_info *sbi) \ { \ return ( \ (sbi->feature_##compat & EROFS_FEATURE_##feature) != 0); \ } EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) 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(compr_head2, incompat, INCOMPAT_COMPR_HEAD2) 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(48bit, incompat, INCOMPAT_48BIT) EROFS_FEATURE_FUNCS(metabox, incompat, INCOMPAT_METABOX) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER) EROFS_FEATURE_FUNCS(shared_ea_in_metabox, compat, COMPAT_SHARED_EA_IN_METABOX) EROFS_FEATURE_FUNCS(plain_xattr_pfx, compat, COMPAT_PLAIN_XATTR_PFX) EROFS_FEATURE_FUNCS(ishare_xattrs, compat, COMPAT_ISHARE_XATTRS) static inline bool erofs_sb_has_xattr_filter_v1(const struct erofs_sb_info *sbi) { return (erofs_sb_has_xattr_filter(sbi) && sbi->xattr_filter_reserved == 0); } struct erofs_inode { erofs_nid_t nid; uint64_t size; uint64_t data_blocks; /* Absolute device offset, or metabox-file offset when bit 63 is set. */ erofs_off_t inode_off; erofs_blk_t startblk; uint32_t generation; uint32_t nlink; uid_t uid; gid_t gid; mode_t mode; __enum_uint8(vtype) vtype; dev_t rdev; time_t mtime; uint32_t mtime_nsec; uint8_t datalayout; uint8_t inode_isize; uint32_t xattr_isize; bool compact_inode; bool dot_omitted; /* Compression fields */ uint16_t z_advise; uint8_t z_algorithmtype[2]; uint8_t z_lclusterbits; uint16_t z_idata_size; erofs_off_t z_fragmentoff; uint64_t z_tailextent_headlcn; uint64_t z_extents; bool z_initialized; /* Chunk-based fields */ uint16_t chunkformat; uint8_t chunkbits; /* Fragment fields */ bool fragment; struct erofs_xattr_cache xattr_cache; }; struct erofs_fid { uint16_t len; uint16_t pad; uint32_t nid_hi; uint32_t nid_lo; uint32_t gen; }; _Static_assert(sizeof(struct erofs_fid) == 16, "EROFS file handle ABI must be 16 bytes"); _Static_assert(sizeof(struct erofs_fid) <= sizeof(struct fid), "struct erofs_fid must fit within struct fid"); #define VTOE(vp) ((struct erofs_inode *)(vp)->v_data) static inline unsigned int erofs_inode_version(unsigned int ifmt) { return ((ifmt >> EROFS_I_VERSION_BIT) & EROFS_I_VERSION_MASK); } static inline unsigned int erofs_inode_datalayout(unsigned int ifmt) { return ((ifmt >> EROFS_I_DATALAYOUT_BIT) & EROFS_I_DATALAYOUT_MASK); } static inline bool erofs_nid_in_metabox(erofs_nid_t nid) { return ((nid & EROFS_DIRENT_NID_METABOX) != 0); } /* Allocated on disk at m_pa. */ #define EROFS_MAP_MAPPED 0x0001 /* Located in metadata. */ #define EROFS_MAP_META 0x0002 #define EROFS_MAP_PARTIAL_MAPPED 0x0004 #define EROFS_MAP_PARTIAL_REF 0x0008 #define EROFS_MAP_FRAGMENT 0x0010 #define EROFS_MAP_FULL(f) \ (!((f) & (EROFS_MAP_PARTIAL_MAPPED | EROFS_MAP_PARTIAL_REF))) #define EROFS_GET_BLOCKS_FIEMAP 0x0001 #define EROFS_GET_BLOCKS_READMORE 0x0002 #define EROFS_GET_BLOCKS_FINDTAIL 0x0004 enum { Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX, Z_EROFS_COMPRESSION_INTERLACED, Z_EROFS_COMPRESSION_RUNTIME_MAX }; _Static_assert(Z_EROFS_COMPRESSION_RUNTIME_MAX <= UINT8_MAX, "algorithm format must fit in uint8_t"); struct erofs_map_dev { struct erofs_device_info *m_dif; erofs_off_t m_pa; unsigned int m_deviceid; uint64_t m_plen; }; struct erofs_buf { void *data; void (*release)(void *); }; #define EROFS_BUF_INITIALIZER { .data = NULL, .release = NULL } /* Buffer and device I/O. */ int erofs_bread(struct erofs_sb_info *sbi, erofs_off_t off, size_t len, void **bufp); int erofs_read_physical(struct erofs_sb_info *sbi, unsigned int device_id, erofs_off_t off, size_t len, void **bufp); void erofs_brelse(void *buf); void erofs_put_metabuf(struct erofs_buf *buf); int erofs_read_metadata(struct erofs_sb_info *sbi, erofs_nid_t nid, erofs_off_t off, size_t len, struct erofs_buf *buf); /* Logical mapping and file data. */ int erofs_map_blocks(struct erofs_sb_info *sbi, struct erofs_inode *vi, struct erofs_map_blocks *map); int erofs_read_data(struct erofs_sb_info *sbi, struct erofs_inode *vi, erofs_off_t loff, size_t len, void **bufp); int erofs_read_data_readahead(struct erofs_sb_info *sbi, struct erofs_inode *vi, erofs_off_t loff, size_t len, bool sequential, void **bufp); int erofs_read_file(struct vnode *vp, struct uio *uio, int ioflag); int erofs_validate_symlink_target(struct erofs_sb_info *sbi, struct erofs_inode *vi); int erofs_readlink_target(struct vnode *vp, struct uio *uio); /* Inode and vnode lifecycle. */ bool erofs_nid_is_valid(struct erofs_sb_info *sbi, erofs_nid_t nid); bool erofs_dirent_type_matches(uint8_t file_type, __enum_uint8(vtype) vtype); int erofs_read_inode(struct erofs_sb_info *sbi, erofs_nid_t nid, struct erofs_inode *vi); int erofs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp); void erofs_xattr_cache_init(struct erofs_inode *vi); void erofs_xattr_cache_fini(struct erofs_sb_info *sbi, struct erofs_inode *vi); /* Directory operations. */ int erofs_readdir_block(struct vnode *vp, struct uio *uio, int *eofflag, int *ncookies, uint64_t **cookies); int erofs_dirent_namelen(const char *blk, uint32_t nameoff, uint32_t endoff, bool trailing, size_t *namelenp); int erofs_validate_dirblock(const char *blk, uint32_t blksz, uint32_t maxsize, uint32_t *ndirentsp); int erofs_lookup(struct vop_cachedlookup_args *ap); /* Compressed mapping and data. */ int z_erofs_fill_inode(struct erofs_sb_info *sbi, struct erofs_inode *vi); int z_erofs_map_blocks(struct erofs_sb_info *sbi, struct erofs_inode *vi, struct erofs_map_blocks *map); void z_erofs_extent_cache_init(struct erofs_sb_info *sbi); void z_erofs_extent_cache_fini(struct erofs_sb_info *sbi); void z_erofs_stream_pool_init(struct erofs_sb_info *sbi); void z_erofs_stream_pool_fini(struct erofs_sb_info *sbi); int z_erofs_stream_ctx_get(struct erofs_sb_info *sbi, uint8_t algorithm, size_t context_size, erofs_stream_ctx_init_t *init, erofs_stream_ctx_fini_t *fini, struct erofs_stream_ctx **ctxp); void z_erofs_stream_ctx_put(struct erofs_stream_ctx *ctx, bool reusable); int z_erofs_stream_ctx_charge(struct erofs_stream_ctx *ctx, size_t bytes); void z_erofs_stream_ctx_uncharge(struct erofs_stream_ctx *ctx, size_t bytes); void *z_erofs_stream_ctx_alloc(struct erofs_stream_ctx *ctx, size_t bytes); void z_erofs_stream_ctx_free(struct erofs_stream_ctx *ctx, void *address); int z_erofs_read_data(struct erofs_sb_info *sbi, struct erofs_inode *vi, erofs_off_t loff, size_t len, void **bufp); int z_erofs_read_uio(struct erofs_sb_info *sbi, struct erofs_inode *vi, struct uio *uio); int z_erofs_decompress(struct erofs_sb_info *sbi, const struct erofs_map_blocks *map, const void *src, size_t srclen, void *dst, size_t dstlen, bool partial); /* Compression configuration. */ int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, const struct erofs_super_block *dsb); /* VOP vectors. */ extern struct vop_vector erofs_vnodeops; extern struct vop_vector erofs_fifoops; #endif /* __EROFS_INTERNAL_H */