EROFS 源码阅读

#erofs in-tree 驱动

in-tree 的代码也是模块的形式,以 module_init 开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module_init(erofs_module_init);
module_exit(erofs_module_exit);

// in erofs_module_init()
err = register_filesystem(&erofs_fs_type);

static struct file_system_type erofs_fs_type = {
.owner = THIS_MODULE,
.name = "erofs",
.init_fs_context = erofs_init_fs_context, // init ->ops and ->fs_private
.kill_sb = erofs_kill_sb, // shutdown a fs
.fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
};
MODULE_ALIAS_FS("erofs");

Kconfig 中包含的一些选项:

  • EROFS_FS_DEBUG DEBUG支持
  • EROFS_FS_XATTR 拓展属性支持
  • EROFS_FS_POSIX_ACL ACL支持
  • EROFS_FS_SECURITY 安全标签支持
  • EROFS_FS_ZIP 压缩支持,默认只支持读取 LZ4 压缩的数据
    • EROFS_FS_ZIP_LZMA 支持读取 microLZMA 压缩的数据
    • EROFS_FS_ZIP_DEFLATE 支持读取 DEFLATE 压缩的数据
    • EROFS_FS_PCPU_KTHREAD 用per-cpu的线程池去作异步数据解压缩
      • EROFS_FS_PCPU_KTHREAD_HIPRI 把这些线程设为高优先级
  • EROFS_FS_ONDEMAND 利用 fscache 实现 on-demand 读

#初始化流程

1
2
3
4
5
6
static const struct fs_context_operations erofs_context_ops = {
.parse_param = erofs_fc_parse_param, // add a fs param
.get_tree = erofs_fc_get_tree, // ~mount a fs
.reconfigure = erofs_fc_reconfigure, // sb reconfiguration
.free = erofs_fc_free, // clean up
};

#内核的 fs_context 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct fs_context {
const struct fs_context_operations *ops;
struct file_system_type *fs_type;
void *fs_private;
struct dentry *root; // the root of fs tree
struct user_namespace *user_ns;
struct net *net_ns;
const struct cred *cred;
char *source; // /dev/sda1 or host:/path, etc.
char *subtype;
void *security;
void *s_fs_info; // user data -> erofs_sb_info
unsigned int sb_flags;
unsigned int sb_flags_mask;
unsigned int s_iflags;
enum fs_context_purpose purpose:8;
...
};

#EROFS 的元数据 erofs_sb_info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
struct erofs_sb_info {
struct erofs_mount_opts opt; /* options */

#ifdef CONFIG_EROFS_FS_ZIP
/* list for all registered superblocks, mainly for shrinker */
struct list_head list;
struct mutex umount_mutex;

/* managed XArray arranged in physical block number */
struct xarray managed_pslots;

unsigned int shrinker_run_no;
u16 available_compr_algs;

/* pseudo inode to manage cached pages */
struct inode *managed_cache;

struct erofs_sb_lz4_info lz4;
#endif /* CONFIG_EROFS_FS_ZIP */
struct inode *packed_inode;
struct erofs_dev_context *devs;
struct dax_device *dax_dev;
u64 dax_part_off;
u64 total_blocks;
u32 primarydevice_blocks;

u32 meta_blkaddr;
#ifdef CONFIG_EROFS_FS_XATTR
u32 xattr_blkaddr;
u32 xattr_prefix_start;
u8 xattr_prefix_count;
struct erofs_xattr_prefix_item *xattr_prefixes;
unsigned int xattr_filter_reserved;
#endif
u16 device_id_mask; /* valid bits of device id to be used */

unsigned char islotbits; /* inode slot unit size in bit shift */
unsigned char blkszbits; /* filesystem block size in bit shift */

u32 sb_size; /* total superblock size */
u32 build_time_nsec;
u64 build_time;

/* what we really care is nid, rather than ino.. */
erofs_nid_t root_nid;
erofs_nid_t packed_nid;
/* used for statfs, f_files - f_favail */
u64 inos;

u8 uuid[16]; /* 128-bit uuid for volume */
u8 volume_name[16]; /* volume name */
u32 feature_compat;
u32 feature_incompat;

/* sysfs support */
struct kobject s_kobj; /* /sys/fs/erofs/<devname> */
struct completion s_kobj_unregister;

/* fscache support */
struct fscache_volume *volume;
struct erofs_fscache *s_fscache;
struct erofs_domain *domain;
char *fsid;
char *domain_id;
};

bdev.c 中负责硬盘块操作

申请super_block

erofs_fc_fill_super 其实是从硬盘上读取数据,初始化user的sb信息

#inode 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const struct inode_operations erofs_generic_iops = {
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_inode_acl = erofs_get_acl,
.fiemap = erofs_fiemap,
};

const struct inode_operations erofs_symlink_iops = {
.get_link = page_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_inode_acl = erofs_get_acl,
};

const struct inode_operations erofs_fast_symlink_iops = {
.get_link = simple_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_inode_acl = erofs_get_acl,
};

#erofs-utils

  • mkfs.erofs 创建一个 erofs 文件系统;
  • fsck.erofs 检查 erofs 镜像的完整性;
  • dump.erofs 导出 erofs 镜像中的相关细节;
  • erofsfuse 用户态

#mkfs

#fsck

#dump

#erofsfuse