用SquashFS存储Portage树

Gentoo系统中的Portage树存储了软件仓库中所有软件的元信息。其中最主要的是Ebuild脚本,它记载了软件的编译方法、依赖关系等。它通常位于/usr/portage

可想而知,这个树中包含了大量的文件,因此占用了很大的磁盘空间。根据我最近的测量,

  • 所有文件的大小总和超过300MiB;
  • 实际占用磁盘空间超过600MiB (ext4)。

但实际上,其中大部分文件都比较小,且属于较易被压缩的文本文件。因此,值得考虑使用一种压缩的文件系统存放Portage树。

SquashFS是一种可压缩的只读文件系统。将Portage树的全部内容放在其中,只需约50MiB的存储空间。

在配置SquashFS的过程中,走了一些弯路。因此,我把操作过程记录在这里,以便日后参考。

准备工作

传统上,Portage把源码包 (distfiles) 和二进制包 (packages) 都放在/usr/portage目录下。它们占用比较大的空间,但不应该被放进SquashFS中。因此,修改make.conf

DISTDIR="/var/cache/distfiles"
PKGDIR="/var/cache/binpkgs"

并把它们移到其他位置:

$ mv /usr/portage/distfiles /var/cache
$ mv /usr/portage/packages /var/cache/binpkgs

只读Portage树

最简单的配置方案是使用只读的Portage树。要使用SquashFS,应在内核选项中启用CONFIG_SQUASHFS

创建SquashFS

Gentoo的官方镜像维护着每天更新的SquashFS镜像。因此,简单的解决方案是从镜像获取SquashFS:

$ wget http://distfiles.gentoo.org/snapshots/squashfs/gentoo-current.xz.sqfs

手动创建SquashFS的方法是,先更新Portage树,然后使用mksquashfs命令(需安装squashfs-tools):

$ mksquashfs /usr/portage gentoo.sfs -comp xz

更多选项参见mksquashfs(1)。 有了SquashFS镜像,就可以删除文件系统中的Portage树了。

挂载SquashFS

$ mount -v -o loop gentoo.sfs /usr/portage

这样得到的是只读的Portage树。可以在此条件下使用Portage管理软件包,但不能更新Portage树。如果要更新,则应该卸载后重新创建/获取SquashFS镜像。

$ umount -v /usr/portage
$ wget ...
$ mount ...

可写Portage树

利用overlay文件系统,可以在节省磁盘空间的前提下实现一个可写的Portage树。 其原理是,配置一个由两个文件系统复合的文件系统:

  • 下层:SquashFS,只读。
  • 上层:ext4或其他任何可写文件系统。

向这个文件系统中写入内容时,写入上层文件系统。读取时,先看上层是否有对应文件,如果没有,则在下层中查找。 当Portage树更新时,只有变化的部分写入了上层。

要使用overlay文件系统,应启用CONFIG_OVERLAY_FS内核选项。

创建Overlay

首先准备3个空目录供overlay使用:

$ mkdir base delta tmp
$ chown portage:portage base delta tmp

它们的用处是:SquashFS将被挂载到base,overlay中的修改将被写入delta,而tmp是overlay内部使用的工作目录(须和delta位于同一文件系统)。

$ mount -v -o loop gentoo.sfs base
$ mount -v -t overlay none /usr/portage \
	-o lowerdir=base,upperdir=delta,workdir=tmp

这时检查/usr/portage的所有者,应为portage

$ stat -c%U:%G /usr/portage/
portage:portage

更新Portage树

禁用Portage的硬链接功能,因为它和overlay不兼容:编辑/etc/portage/repos.conf/gentoo.conf

[gentoo]
...
sync-allow-hardlinks = no

之后就可以像使用普通文件系统一样,更新Portage树:

$ emerge --sync
$ du -hd0 gentoo.sfs delta/
51M     gentoo.sfs
17M     delta/

上面的例子中,一次更新带来了17M的变化。

合成新SquashFS

当上层文件系统中的内容较多时,可以考虑合成一个新的SquashFS镜像,并丢弃上层文件系统。

$ mksquashfs /usr/portage gentoo.sfs.1 -comp xz
$ umount /usr/portage
$ umount base
$ mv gentoo.sfs gentoo.sfs~
$ mv gentoo.sfs.1 gentoo.sfs
$ find delta/ -delete

后续

可以写init scripts,实现:

  • 开机加载overlay;
  • 关机卸载overlay;
  • delta/超过一定大小后,生成新的SquashFS镜像。

这样,对用户来说就是透明的。

即使是只读Portage树,在crontab中写一个每天定时更新SquashFS镜像的任务,也可以起到很好的效果。


分享