发布于 ,更新于 ,文章内容可能已经过时

在启用 ZSTD 压缩的 ZFS 根分区上安装 ArchLinux 并配置 Windows 双启动

ZFSBootMenu 基础使用 和这篇文章的最后部分相同。 本方案已经被实际测试过,完全可用,但是建议在有 Linux 基础的情况下折腾 ZFS,因为没准有某个地方我会忘记修改...

总览

分区大概长这样

1
2
3
4
分区1 300M FAT16 EFI
分区2 128G ZFS ArchLinux
分区3 128G NTFS Windows
分区N **G **FS DATA // 其他分区
复制

然后 ZFS 池里面长这样

1
2
3
4
5
6
zroot
├─ROOT
| ├─voidlinux // 实际上可以在这个池里安装多个 Linux,本处计划把所有 Linux 根分区数据集放在 zroot/ROOT/ 里
| └─archlinux
└─data
└─home // 存放 /home
复制

ZFS 池那块看不懂没关系,只需要跟着文章做就行

安装前

准备一个有 ZFS 支持的 archiso,这里我们提供两个方案

CachyOS LiveCD(推荐)

CachyOS 的 Sourceforge 界面 下载带 GUI 的 LiveCD(它的 CLI 安装器没 ZFS 支持),然后扔进 U 盘重启进入即可

1
2
3
4
5
6
7
8
9
sudo modprobe zfs # 加载 ZFS 模块

sudo su # 切换到 root 用户

timedatectl set-ntp true # 同步时间

vim /etc/pacman.d/mirrorlist # 改镜像站
# 开头添加
Server = https://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
复制

archiso-zfs

此处使用 eoli3n 的 archiso-zfs 项目

首先下载一个官方的 ArchLinux LiveCD,然后重启进入

联网

1
iwctl # 进入 iwctl 命令行界面
复制

下面的命令在 iwctl 中输入

1
2
3
4
5
device list # 列出可用设备
# 假设上面列出的设备是 wlan0
station wlan0 scan
station wlan0 connect SSID # 连接名为 SSID 的网络
exit
复制

验证联网

1
2
ping www.baidu.com
timedatectl set-ntp true # 同步时间
复制

加载 ZFS 模块

1
curl -s https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init | bash -x
复制

如果连接 github 有问题,则运行下面的命令替代

1
curl -s https://ghproxy.com/https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init | bash -x
复制

执行过程因为网络原因会比较慢

改镜像站

1
2
3
vim /etc/pacman.d/mirrorlist
# 开头添加
Server = https://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
复制

至此,环境准备完毕,下面的操作不受 livecd 影响

格式化

此处认为你已经分好区了,总体需要三个分区

  • ESP(EFI) 分区,300M,打了 ESP 标签(可以用 cfdisk 打),此处举例为 /dev/nvme0n1p1
  • Linux 分区(ZFS 池),30+G,此处举例为 /dev/nvme0n1p2
  • Windows 分区(如果不需要安装 Windows 就不用建),40+G,此处举例为 /dev/nvme0n1p3

创建 ZFS 池

  • ashift = 12 代表 4096 字节扇区大小,9 代表 512 扇区大小,13 代表 8192 字节扇区大小,在 4096/8192 扇区大小的 SSD 上设置 9 会导致性能损失,在 512 字节扇区大小的硬盘上设置 12/13 会导致容量损失,扇区大小可以通过 fdisk -l(不准)或者 diskgenius 这类工具查看
  • dedup=on 为去重功能,可能会占用较大 RAM,低配机子可以把这行删掉
  • compression=zstd 为压缩功能,zstd 目前来看压缩率和性能损失比较平衡,在意性能可以改为快速压缩算法 lz4(gzip 压缩率和性能都比不上 zstd)(好吧我后来在乎性能换成 lz4 了,实际上压缩率也不算太差)
  • atime=off 我们不需要知道最后一次访问某个文件的时间。
  • primarycache=metadata 默认为 all,为了减小 ARC 带来的内存压力改为 metadata
  • secondarycache=none 默认为 all,L2ARC 感觉对桌面端弊大于利,直接取消。
  • checksum=blake3 默认为 onblake3 是一种高性能加密哈希算法,比默认的 SHA-2 系列快很多。

其他照做即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
zpool create -f -o ashift=12           \
-O acltype=posixacl \
-O atime=off \
-O xattr=sa \
-O dnodesize=legacy \
-O normalization=formD \
-O mountpoint=none \
-O canmount=off \
-O devices=off \
-O compression=zstd \
-O dedup=on \
-O checksum=blake3 \
-O primarycache=metadata \
-O secondarycache=none \
-R /mnt \
zroot /dev/nvme0n1p2
复制

创建数据集

1
2
3
4
zfs create -o mountpoint=none zroot/data
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/archlinux
zfs create -o mountpoint=/home zroot/data/home
复制

测试 zpool 是否能够导入导出

1
2
zpool export zroot
zpool import zroot -R /mnt
复制

挂载 zpool

1
2
zfs mount zroot/ROOT/archlinux
zfs mount -a
复制

设置启动数据集

1
zpool set bootfs=zroot/ROOT/archlinux zroot
复制

设置 zpool 缓存

1
2
3
4
zpool set cachefile=/etc/zfs/zpool.cache zroot
mkdir /mnt/etc
mkdir /mnt/etc/zfs
cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache
复制

查看是否有挂载上

1
df -h
复制

输出

1
zroot/ROOT/archlinux   30G  128K   30G   1% /mnt
复制

格式化 EFI 分区

注意此处挂载点不可以设置成 /boot1

1
2
3
mkfs.vfat /dev/nvme0n1p1
mkdir /mnt/efi
mount /dev/nvme0n1p1 /mnt/efi
复制

安装

这部分需要你在 /etc/pacman.conf 里添加 archzfs 源或者按照一刀斩的博客配置 CachyOS 源,此处不再赘述

安装基本软件包

如果是 Intel 的 CPU 就把 amd-ucode 换成 intel-ucode

此处使用 zfs-linux 包有可能会因为版本不相同然后挂掉,所以如果你添加了 CachyOS 的软件源,那么我推荐你使用 CachyOS 的自定义内核(它的内核和 zfs 模块同时编译打包,就不会出现版本不统一的问题)(最主要还是因为安装 zfs-linux 还得启用 v3 源),有多种任务调度器可选,比如 BMQ PDS TT 等,还有 LLVM LTO 编译的版本

使用 CachyOS 内核的话直接改包即可,比如我想用 linux-cachyos-pds,那么把下面 linux linux-headers zfs-linux 换成 linux-cachyos-pds linux-cachyos-pds-headers linux-cachyos-pds-zfs 即可

如果你不想用 CachyOS 的内核,也不想因为 zfs 模块和 linux 内核版本不统一而滚挂,那么可以使用 dkms 模块,把 zfs-linux 替换为 zfs-dkms 即可,这个的缺点是构建 dkms 模块时会风扇狂转(理论上任何内核都可以用这个当 zfs 内核模块)

1
pacstrap /mnt base linux-firmware linux linux-headers zfs-linux base-devel neovim os-prober amd-ucode openssh wget networkmanager zfs-utils
复制

基础安装

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
# 配置 /etc/fstab
genfstab -U /mnt >> /mnt/etc/fstab
# 验证 /etc/fstab
cat /mnt/etc/fstab

# chroot 进 ArchLinux
arch-chroot /mnt

# 设置zpool缓存
zpool set cachefile=/etc/zfs/zpool.cache zroot

# 设置时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
hwclock --systohc
date

# 设置语言
echo -e "\nen_US.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\nzh_TW.UTF-8 UTF-8" >> /etc/locale.gen

# 应用配置
locale-gen

# 设置默认语言
echo -e "\nLANG=en_US.UTF-8\n" >> /etc/locale.conf

# 设置root密码
passwd

# 添加非 root 用户
pacman -S fish # 如果不想用 fish 可以跳过这一步并把下一步的 fish 字段换成 bash
useradd -m -G wheel -s /bin/fish user # user 替换为你的用户名
passwd user # 设置密码
sed -i "s|#%wheel ALL=(ALL) ALL|%wheel ALL=(ALL) ALL|g" /etc/sudoers # 添加 sudo 权限,命令可能无效,请自行查询如何给 wheel 用户组添加 sudo 权限


# 添加 multilib 和 archlinuxcn 仓库
arch='$arch'
echo -e "\n[multilib]\nInclude = /etc/pacman.d/mirrorlist\n\n[archlinuxcn]\nServer = https://mirrors.bfsu.edu.cn/archlinuxcn/$arch" >> /etc/pacman.conf
复制

配置内核钩子

重点部分! 编辑 /etc/mkinitcpio.conf,直接在 HOOKS=(......) 里面加上 zfs

1
2
nvim /etc/mkinitcpio.conf
HOOKS=(base udev autodetect modconf block zfs filesystems keyboard fsck)
复制

编辑完直接借用 ArchLinux 的极为人性化的脚本生成即可

1
mkinitcpio -P
复制

设置 zfs 服务以及网络管理服务

1
2
3
4
5
6
systemctl enable zfs.target
systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target
systemctl enable sshd
systemctl enable NetworkManager
复制

配置 ZFSBootMenu 引导

(需要在 chroot 中完成)
重点部分!
详细了解可以看我之前那篇在 UEFI ArchLinux 下使用 ZFSBootMenu 作为引导器(可双启动)
在这里我们使用预构建好的 EFI 文件因为我没玩明白 ZFSBootMenu,经常出现换内核再构建就会炸引导的问题,同时不能做到启动时换内核

首先下载预构建好的 ZBM efi 引导文件 (访问不了可以把 https://github.com/ 换成 https://ghproxy.com/https://github.com/)

1
2
3
mkdir /efi/EFI
mkdir /efi/EFI/ZBM
wget https://github.com/zbm-dev/zfsbootmenu/releases/download/v2.0.0/zfsbootmenu-release-vmlinuz-x86_64-v2.0.0.EFI -O /efi/EFI/ZBM/zfsbootmenu.efi
复制

再进行一个简单的配置

1
zfs set org.zfsbootmenu:commandline="rw" zroot/ROOT
复制

这样就做到了启动(如果没有双启动的需求没必要进行下一步了)

配置 rEFInd 以实现与 Windows 双启动

安装 refind

1
2
pacman -Sy refind git
refind-install
复制

这样重启之后就能双启动了
但是你还可以美化一下,安装 nord 主题(非必要)

1
pacman -U https://mirror.cachyos.org/repo/x86_64/cachyos/refind-theme-nord-1.1.0-1-any.pkg.tar.zst
复制

结束

退出 chroot

1
exit
复制

解挂载

1
2
3
umount /mnt/efi
zfs umount zroot/ROOT/archlinux
zfs umount -a
复制

导出 zfs 池

1
zpool export zroot
复制

(导出没成功也没关系,直接重启即可) 重启

1
reboot
复制

然后你的 archlinux 就可以正常使用了

后记

还是在年前完成了虚拟机上的测试,能够完美安装,原来写的还是有点低级错误的
Hyper-V 上安装可能会涉及到 pacman 检测不到架构之类的问题,因此启用 archlinuxcn 源需要你在 /etc/pacman.confArchitecture = auto 中的 auto 为你的架构,如 x86_64 x86_64-v3
另外不启用 CachyOS-v3 源,只启用 CachyOS 源也可以安装 CachyOS 的优化内核,但是没有 lto 版本
以及我个人宣布,这是本博客 2022 年的最佳博文


  1. 原因是 ZFSBootMenu 需要从 /boot 加载内核,而 ZBM 的 initramfs 启动时大概不会挂载 ESP 分区(我之前这么干寄了↩︎