支持华为之——Huawei EROFS 初探

支持华为之——Huawei EROFS 初探

前言

华为作为中国代表性的技术型企业,一直在不断推出自己的技术实现,并努力推广到世界,这一点是非常值得称赞的。近日华为又作为中美贸易战中美国主要针对的中国企业,受到了美国的各种封禁。但是面对顽强不懦弱的华为,面对国家民族利益的选择,我只能用一句话来表达我们中华儿女的决心——“苟利国家生死以,岂因祸福避趋之。”

系统这篇文章能带你走入华为EROFS的大门,让有能力有兴趣的人可以自发的后续支持此项目。哪怕你只是安装使用测试反馈都可以。

好,我们言归正传。从大概上游Linux 4.19左右,邮件列表开始出现一个EROFS的东西,不断有邮件的往来。因为太小众,所以当时没有太留意,只是因为EROFS这个名字和写只读文件系统时返回的错误名字一样,所以就留下了印象,其实都没注意到是华为的人做的。最近华为推出新手机,并宣扬自己为手机系统新写的文件系统的新闻不断发酵。我才开始注意到EROFS原来是华为的人写的,并且已经被merge到了Linux内核主线。

作为一个从事操作系统行业,文件系统方向的人,面对这样一个由国人推出的已经进了Linux项目主线的新文件系统,我觉得我有必要稍微关注一下。于是在晚上刚开完会后,现在是2019-03-27晚上21:18分,我开始了第一次对EROFS的初探。为什么要写上时间?因为我下面的一些操作可能会在项目日趋完善后出现变化,所以时间点变相代表我操作的“版本号”。

获得信息

这是一个全新的项目,所以怎么使用我也毫无头绪,网上文档及其少,用Google搜索Linux EROFS得到的大部分是Linux怎么处理EROFS错误,或者华为发布EROFS的新闻。新闻内容没什么参考价值,所以erofs在邮件列表的邮件成了重要的信息来源:

'[NOMERGE] [RFC PATCH 00/12] erofs: introduce erofs file system'marc.info

还有一个LWN上关于EROFS的介绍:

https://lwn.net/Articles/760964/lwn.net

但是因为我是付费的用户,所以能打开这个文章,不知道一般用户是不是能打开。如果打不开也没关系,内容并不多,还不如看上面的邮件列表的邮件。

从一些内容上我们知道了EROFS还有一个用户态工具,我找了一下,项目地址在

Userspace utilities for linux-erofs file systemgit.kernel.org图标

有用的信息我暂时就找到这三个,这已经够我看一阵子了,今晚是肯定看不完。我们下面还是先完成初探的内容,将这个新的文件系统用起来。

尝试使用

因为EROFS已经进的Linux的主线,所以找到并编译安装它是使用它第一件要做的事情

# git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
# make menuconfig

在进入config界面后,我并不知道EROFS的编译选项在哪,所以先搜索EROFS,看到如下图所示:

搜索EROFS

从描述可以看出那个EROFSFS基本就是我们要找的,它没有在filesystem目录下,而是在Device Drivers下面,而且目前还作为Staging drivers存在。嗯……看来我要冒着很大的Crash的风险来试试它了。按照上面所示我们找到EROFS_FS的编译选项的位置:

EROFS 编译选项

我们选择将其编译为模块<M>。由于第一次使用,下面的编译子选项我就先默认了。保存退出,开始编译安装:

# make -j32 && make -j16 modules_install && make install

(此处省略一个小时,/me 先小睡一会。。。)

。。。。

。。。。

好了,编译好了,没有出现编译错误。由于当前正是Linux的5.1.0-rc2阶段,所以装的kernel默认是/boot/vmlinuz-5.1.0-rc2+,我们选择将其默认启动后重启系统:

# grubby --set-default=/boot/vmlinuz-5.1.0-rc2+
# shutdown -r now

系统boot起新的kernel后erofs不是被自动加载的(毕竟它还是个staging阶段的driver),我们把它加载上来:

# find /lib/modules/`uname -r` -name erofs*
/lib/modules/5.1.0-rc2+/kernel/drivers/staging/erofs
/lib/modules/5.1.0-rc2+/kernel/drivers/staging/erofs/erofs.ko
# lsmod|grep erofs
# modprobe erofs
# dmesg|tail
...
[19474.968155] erofs: module is from the staging directory, the quality is unknown, you have been warned.
[19474.987076] erofs: initializing erofs 1.0pre1
[19474.992463] erofs: successfully to initialize erofs
# lsmod|grep erofs
erofs                 147456  0

嗯....加载上了,它“贴心”的还提示我"the quality is unknown, you have been warned"。下面该做什么呢?有了这样一个module,我们要想办法用起来。正好作者还提供了一个用户层工具erofs-utils,我们把那个项目也clone下来:

# git clone git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
Cloning into 'erofs-utils'...
remote: Counting objects: 147, done.
remote: Compressing objects: 100% (143/143), done.
remote: Total 147 (delta 83), reused 2 (delta 0)
Receiving objects: 100% (147/147), 55.02 KiB | 678.00 KiB/s, done.
Resolving deltas: 100% (83/83), done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.
# ls
# git branch
# git branch -a
  remotes/origin/mkfs-dev

空的?作者也真是心大,看来这确实是一个初级阶段的项目,连HEAD refer都没弄好。好在作者没有忘记push mkfs-dev分支,我们切到这个分支上看看。

# git checkout -b mkfs-dev remotes/origin/mkfs-dev
Branch 'mkfs-dev' set up to track remote branch 'mkfs-dev' from 'origin'.
Switched to a new branch 'mkfs-dev'
# ls
AUTHORS  autogen.sh  ChangeLog  configure.ac  COPYING  include  Makefile.am  mkfs  NEWS  README

嗯,这回有东西了。老规矩,未知的东西先看文档。也没有什么特别的manual文档,那就看README吧:

下面引用的文档内容版权归文档作者所有:

mkfs.erofs

mkfs.erofs is a user-space tool to create erofs filesystem images.

It can create 2 main types of erofs images, compressed and uncompressed:
- For compressed images, it is able to integrate several compression
algorithms, lz4 is supported according to the current erofs kernel
implementation.
- For uncompressed images, it can decide whether the last page of
a file should be inlined or not properly [1].

Note that mkfs.erofs can only be linked statically with lz4 library
due to the dependency of experimental lz4hc apis which were added in
lz4 1.8.0. Anyway, it's a good start to begin with building the latest
lz4 library statically first. :)

Dependencies
lz4-1.8.0 or above

How to build with lz4 static library
./configure --with-lz4=<lz4 install path>
eg. if lz4 lib has been installed into fold of /usr/local/lib
./configure --with-lz4=/usr/local/lib && make
On Fedora, static lz4 can be installed using:
yum install lz4-static.x86_64
To build you should run this first:
$ ./autogen.sh
$ ./configure
$ make

先看介绍和编译部分,需要lz4的库,版本要求lz4-1.8.0以上。我先看看我的repo里有没有:

# yum info lz4
....
Available Packages
Name         : lz4
Version      : 1.8.1.2
Release      : 4.el8
Arch         : x86_64
Size         : 92 k
Source       : lz4-1.8.1.2-4.el8.src.rpm
Repo         : beaker-BaseOS
Summary      : Extremely fast compression algorithm
URL          : https://lz4.github.io/lz4/
License      : GPLv2+ and BSD
Description  : LZ4 is an extremely fast loss-less compression algorithm, providing compression
             : speed at 400 MB/s per core, scalable with multi-core CPU. It also features
             : an extremely fast decoder, with speed in multiple GB/s per core, typically
             : reaching RAM speed limits on multi-core systems.

嗯,很不错,我大Red Hat (已经被IBM买走了T_T)的最新系统支持这个库,版本正好在1.8以上。省去我自己下载编译的功夫了,我们将lz4及其库文件都装上:

# yum install lz4 lz4-libs lz4-devel lz4-static

然后尝试编译erofs-utils,文档上写的很清楚,我们照着执行一下试试看有没有问题:

# cd erofs-utils
# ./autogen.sh
# ./configure
# make -j4

Lucky! 没有问题!我们得到了重要的mkfs文件:

# ls mkfs/mkfs.erofs -l
-rwxr-xr-x. 1 root root 239480 Mar 27 11:36 mkfs/mkfs.erofs
# ./mkfs/mkfs.erofs
mkfs.erofs 0.1   Mar 27 2019 11:36:50

Usage:
    [-z <compr_algri>] [-d <dbglvl>]
    [target path] [source directory]

好吧,虽然它没有--help/-h这个选项,但是它还是大方的告诉了我自己的版本号和usage。再来看文档:

Usage:
$ ./mkfs.erofs
mkfs.erofs v1.0 Nov 17 2018 19:47:21

Usage:
[-z <compr_algri>] [-d <dbglvl>]
[target path] [source directory]

-d -- set debugging level <dbglvl>
-z -- enable <compr_algri> compression (only lz4hc is supported)

Target path, source directory are both needed.

文档解释了-d和-z两个选项的意思,一个是设置debug的级别,一个是选择压缩算法,但是好像目前就只有lz4hc一个被支持,所以这两个选项我们先都不尝试了。然后target path和source directory是都需要的。那我们就试一下好了:

  • 先准备一个测试用文件(虚拟设备用),和一个测试用目录。对应上面的target path和source directory。为了测试,我们给新目录里随便拷贝一些内容:
# dd if=/dev/zero of=/home/erofs_disk bs=512 count=23000
23000+0 records in
23000+0 records out
11776000 bytes (12 MB, 11 MiB) copied, 0.306837 s, 38.4 MB/s
# mkdir /home/srcd
# cp README /home/srcd
# cp COPYING /home/srcd
# cp ChangeLog /home/srcd
# cp Makefile /home/srcd
  • 使用mkfs.erofs,将目录的内容“压缩”到文件image里:
# ./mkfs/mkfs.erofs /home/erofs_disk /home/srcd/
        c_version:           [0.1   Mar 27 2019 11:36:50]
        c_img_path:          [/home/erofs_disk]
        c_src_path:          [/home/srcd]
        c_dbg_lvl:           [       0]
        c_dry_run:           [       0]
        c_alg_name:          [    none]
        c_compr_maxsz:       [  921600]
        c_compr_lvl:         [       0]
        c_compr_boundary:    [     128]
        c_compr_ratio_limit: [     100]
  • 上面我们已经加载了erofs模块,现在我们可以挂载我们这个文件系统来看看了。因为是用文件虚拟的设备,所以做loop设备使用:
# mount -t erofs /home/erofs_disk /mnt/scratch -oloop
# dmesg|tail
[21656.252653] loop: module loaded
[21656.288268] erofs: read_super, device -> /dev/loop0
[21656.293824] erofs: options -> (null)
[21656.298229] erofs: root inode @ nid 0
[21656.302805] erofs: mounted on /dev/loop0 with opts: (null).
# mount|grep erofs
/home/erofs_disk on /mnt/scratch type erofs (ro,relatime,user_xattr,acl)
  • 挂载成功了,可以看到里面我们拷贝过的文件。
# ls -li /mnt/scratch
total 48
  79 -rw-r--r--. 1 root root     0 Mar 27 11:51 ChangeLog
   4 -rw-r--r--. 1 root root 18729 Mar 27 11:51 COPYING
  80 -rw-r--r--. 1 root root 25649 Mar 27 11:51 Makefile
1408 -rw-r--r--. 1 root root  3744 Mar 27 11:51 README
  • 下面我们尝试在这个只读文件系统上做一些写操作:
# echo > /mnt/scratch/file
bash: /mnt/scratch/file: Read-only file system
  • 果然不能写。再尝试以读写的方式重新挂载试试:
# mount -t erofs /home/erofs_disk /mnt/scratch -oremount,rw
# cat /proc/mounts |grep erofs
/dev/loop0 /mnt/scratch erofs ro,relatime,user_xattr,acl 0 0
# dmesg|tail
# echo > /mnt/scratch/file
bash: /mnt/scratch/file: Read-only file system

没报什么错,但是也没有被改成rw。

  • 不死心,卸载文件系统重新尝试以指定rw的方式直接挂载试试:
# umount /mnt/scratch
# dmesg|tail
[22737.057138] erofs: unmounted for /dev/loop0
# mount -t erofs /home/erofs_disk /mnt/scratch -oloop,rw
# echo $?
0
# dmesg
[22818.902072] erofs: read_super, device -> /dev/loop0
[22818.907548] erofs: options -> (null)
[22818.911625] erofs: root inode @ nid 0
[22818.915838] erofs: mounted on /dev/loop0 with opts: (null).
# cat /proc/mounts |grep erofs
/dev/loop0 /mnt/scratch erofs ro,relatime,user_xattr,acl 0 0
# echo > /mnt/scratch/file
bash: /mnt/scratch/file: Read-only file system

嗯,很坚挺,打死不动^_^

结束语

作为初探,今天就先放过它吧,改天再想办法让他panic(如果我有时间的话)。原理性的东西其实也并不是多新的技术,应该也不会跳出一直以来compression filesystem的圈。实现细节也还没怎么看,好像和ext4对metadata的组织有点类似,但是因为是只读的,所以可以省去很多东西,但是因为压缩功能,要新增一些东西。总之今天就先到这吧,每天都从中国同事工作的时间一直干到美国同事快下班,唉,说多了都是泪,睡觉了。


更多内容请参阅:

醉卧沙场:README - 专栏文章总索引

编辑于 2019-06-02

文章被以下专栏收录