用Btrfs为根分区创建快照
得益于Btrfs的CoW特性,它创建快照的开销可以非常小,所以我觉得它非常适合作为根分区的文件系统。
子卷(subwolume)
“A Btrfs subvolume is not a block device (and cannot be treated as one) instead, a Btrfs subvolume can be thought of as a POSIX file namespace.”
- 最顶层的子卷
- ID: 5
- 无法被删除,无法被替换
- 路径: “/”
- 其它子卷
- 挂载在顶层子卷的下方
- 可以在文件系统中移动路径,但ID不变
使用子卷
- 创建一个子卷
btrfs subvolume create /path/to/subvolume
可以像mkdir
一样使用--parents
参数
2. 列出一个路径下的所有子卷
btrfs subvolume list -p path
- 删除一个子卷 btrfs subvolume delete /path/to/subvolume
分区的储存空间还够吗?
一般的系统工具不会给出Btrfs分区的准确用量信息。需要用下面的命令:
# as superuser
btrfs filesystem usage /
# as normaluser
btrfs filesystem df /
使用快照备份和恢复根分区
参考
如果已经用了顶层子卷作为根分区怎么办
如果你已经把顶层子卷当成了系统根路径,要知道顶层子卷是唯一特殊的,无法通过重命名的方式替换,请通过一下步骤改用次级子卷作为根分区:
- 修改配置重新生成GRUB,以及修改@current子卷下的fstab
- 在
/etc/default/grub
中找到GRUB_CMDLINE_LINUX
这一行,改为
GRUB_CMDLINE_LINUX="rootflags=subvol=/@current"
- 重新生成GRUB:
sudo grub-mkconfig -o /boot/grub/grub.cfg
- 修改fstab
# 比如这是原来的根目录挂载
UUID=******* / btrfs rw,relatime,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/ 0 0
# 现在改成
UUID=******* / btrfs rw,relatime,ssd,discard=async,space_cache=v2,subvolid=5,subvol=/@current 0 0
- 生成顶层子卷的快照(命名为
@current
), 然后重新启动系统
sudo btrfs subvolume snapshot / /@current
可以这样列出所有子卷
sudo btrfs subvolume list /
- 最后挂载顶层子卷并删除其中除了
@current
以外所有内容
sudo mount /dev/nvme0n1p3 /mnt
## 如果挂载的不是顶层子卷,用-o选项,指定subvol的值为快照子卷的路径,或指定subvolid的值为快照子卷的ID
sudo chatter -i /mnt/etc/resolv.conf
rm -rf /mnt/[a-z]*
ls /mnt
创建快照的脚本
#!/bin/bash
system_root_device=$(findmnt -n -o SOURCE /)
system_root_device=${system_root_device%%[*}
snapshot_date=$(date +'%Y-%m-%d_%H:%M:%S')
mount -m "$system_root_device" /mnt/@top_subvol
btrfs subvolume snapshot / "/mnt/@top_subvol/@snapshot$snapshot_date"
snapshots=( $(ls -dr /mnt/@top_subvol/@snapshot*) )
echo "${snapshots[@]}"
if [[ ${#snapshots[@]} > 2 ]]; then
for snapshot in ${snapshots[@]:1}; do
btrfs subvolume delete "$snapshot"
done
fi
umount /mnt/@top_subvol
rmdir /mnt/@top_subvol
在对根分区执行有风险的操作之前记得执行这个脚本哦
使用钩子让pacman在更新前调用创建快照的脚本
创建文件/etc/pacman.d/hooks/update_snapshot.hook
内容如下:
[Trigger]
Operation = Upgrade
Type = Package
Target = *
[Action]
Description = Creating Btrfs snapshot of / before upgrade...
When = PreTransaction
Exec = /home/poshd/all/local/bin/update_snapshot
如果@current子卷损坏,无法正常启动系统,怎么办?
- 开机一般会自动进入救援模式 如果不放心,可以像这样确定自己的系统确实支持btrfs文件系统
~ # lsinitcpio /boot/initramfs-linux.img | grep btrfs
usr/lib/modules/6.9.5-arch1-1/kernel/fs/btrfs/
usr/lib/modules/6.9.5-arch1-1/kernel/fs/btrfs/btrfs.ko.zst
usr/bin/fsck.btrfs
usr/lib/udev/rules.d/64-btrfs.rules
- 挂载根分区硬盘的顶级子卷
- 重命名@current为@abandoned
- 重命名最新的快照为@current
- 重启进入linux系统,确认恢复到快照,则挂载顶级子卷后用btrfs命令删除@abandoned。