btrfs parent transid verify error的玄学修复记录
错误排查
小伙伴大半夜找我说暗影大人的视频无法播放了,我去确认了一下,jellyfin转码烧录mks字幕确实出问题了,但是让客户端不转码直接本地播放是可以播放的,就没在意,直到第二天一觉醒来,他又来说问题了,这次不是视频无法播放,而是jellyfin打不开了
我第一反应是ddns寄了,或者我路由网络又出毛病了(
昨晚才处理好的Clash DNS解析啊),但是一个测试发现并没有,只是所有web服务都无法访问了,ssh看了下docker,好家伙docker寄了好端端的docker怎么会寄,考虑到docker容器所在的分区曾经寄过,我dmesg看了下,嗯,磁盘分区寄了,症状和上次类似,只是这一次寄得更彻底了。
首先,寄了的问题磁盘分区是ArchLinux上的sdb1
:
|
|
而这是dmesg
记录的一部分日志,因为这是事后回忆整理,我留下的记录并不是很多,悲
|
|
尝试找到错误文件
可以看到错误首先是114737152
这个inode对应的文件校验错误,那么首先应该找到它,好在分区虽然寄了,但是因为forced readonly
所以依旧能挂载并且可读,先一个find ./ -num 114737152
尝试找到它,结果并没有像以前寄的时候那样找到对应的文件,而是直接打印了一大堆的报错
|
|
通过btrfs工具查看错误
btrfs虽然是以不成熟和不稳定且性能一般闻名于世,不过还是提供了一些工具来尝试解决常见问题
通过谷歌搜索,我找到了一个类似问题的疑难解答页面,本来以为是人家单独列出来肯定是常见好救的,结果它建议我备份数据,这是一个永久性错误,并且原因不明
这不能够啊!
这个文档里虽然没有提供任何修复方案,但是记录了btrfs的各种命令用法,倒也不算没有一点用处
确认一下btrfs记录到多少个错误
btrfs dev stats /dev/sdb1
跑一下,上一次分区错误的时候,这里记录了几百个错误,但是没有处理好,我最后格式化分区了,出乎意料的,这次一个错误都没有发现
|
|
虽然不知道这意味着什么,但没有错误记录,也许还有救,在网上找一找前人的经验,比方说StackOverflow上的帖子
尝试usebackuproot
按照帖子里的一个答案,只读挂载时带上
usebackuproot
:mount -t btrfs -o ro,usebackuproot /dev/sdb1 /home/cache
如果能够成功挂载,则去掉只读的ro
重新挂载,能挂载上说明修复了
我尝试只读挂载成功并没有问题,毕竟我本来就能只读挂载,此时再次进入/home/cache
目录尝试读取文件,依旧是Input/output error
,抱着侥幸心理,我尝试不指定只读挂载,即mount -t btrfs -o usebackuproot /dev/sdb1 /home/cache
,不出意料的发生了错误,但是错误信息我没保留下来,所以没法展示了
格式化前的死马当活马医
前文说过,我这个分区不是第一次出现这种错误,上一次我尝试了各种btrfs的命令也没修复成功,但成功把数据给备份出来了 而这一次我讲数据复制出来都会发生错误,其实并没有什么动力去研究,毕竟有一次失败在前,而且这次连备份都做不到,甚至产生放弃btrfs,格式化回ext4的想法
就在我即将运行mkfs.ext4 /dev/sdb1
时,我突然想到这次btrfs dev stats
并没有报错,虽然出现了上次没有出现的Input/output error
,但是btrfs本身的情况也许没那么糟糕,上次用过的命令可以试试
btrfs
有不少的子命令工具可以做一些诸如重建树或者擦除
先跑一个btrfs scrub status /home/cache
看看结果
|
|
没有错误
btrfs有一个不建议使用的命令可以尝试修复错误,即
btrfs check --repair /dev/sdb1
,我上一次也执行过,但并没有修复我的问题
但这次既然没有错误,也就是有尝试的价值
直接运行btrfs check --repair --force /dev/sdb1
,果然跟上一次什么变化都没有的输出不同,它输出了很多修复节点的信息,也没有保存下来
运行完成之后,我尝试可读写挂载,问题依旧
峰回路转
失望也带着绝望,我只能格式化了,并且这次格式化我不打算再使用btrfs了,它已经两次在同一个分区上寄了,mkfs.ext4 /dev/sdb1
,跟数据和btrfs说拜拜吧 其实我挂载的路径是cache就说明了没有什么重要数据,仅仅是缓存分区,随便格的那种
出乎意料的,格式化没有开始,设备繁忙中
我确认了一下,我已经卸载设备了,并没有挂载到目录,btrfs dev stats
也显示设备被占用
也许是check占用了设备没有释放,此时的我也没有心情去关心了,只想快点格了然后重建docker容器恢复服务
关闭docker服务开机自启,关闭systemd的开机自动磁盘挂载,重启设备一气呵成
开机之后,我正要格式化,又想,也许它好了呢?
于是我只读挂载了一下,正常挂载,甚至执行ls
的时候都没有Input/output error
了,并且dmesg
也没有任何错误信息,我心情有点小激动,二话不说systemctl start docker
,看看docker能起来不,起不来,依旧是报错,报错信息我都懒得看了
等会,我现在是只读挂载,docker怎么可能起来!!
改成可读写挂载,docker启动了!!服务上线了!!
后续
访问一下jellyfin,发现页面有了,但登录页打不开,F12
看一下原因,少了一个js文件,直接重建容器,一切都正常了,也许btrfs check --repair
给我移除了无法通过校验的文件
准确说我不清楚我是怎么修复的,我只能靠回忆记录下这个并没有多少操作的过程,其中我如果有那么一次没有想再看看分区是不是好了,或者check之后设备不是繁忙中,我恐怕不敢相信我居然能看到它恢复正常,这大概就是不放弃吧(bushi
记一次Rust静态编译
Aio服务器搭建
个人Aio服务器搭建(未完待续)
以下是碎碎念,建议跳过
百度云限速、360云盘迅雷云盘等相继关闭;QQ音乐、网易云音乐版权竞争,歌单里的歌三天两头灰色,独占的独占,曲库缺失的缺失,为了听歌还要每个平台都开会员,并且体验依旧割裂;爱奇艺异军突起、腾讯视频独霸江湖、优酷抱紧了老剧,哔哩哔哩看个纪晓岚标注着1080P事实上并不达标;广电要求影视作品一律先审后播,b站在抽帧黑幕圣光之后直接连追番都不行了,没法同步上映……与此同时,网上一大堆家庭NAS方案层出不穷……
所以我不禁开始思考,已经在上班的我,是时候回收一下中学的梦想————想要一台自己的服务器。
常年的网易云会员,b站会员现在也都已经过期了,促使我不再续费的原因,不外乎网易云越来越多的灰色,哔哩哔哩越来越少且不一定能同步更新的番,老实说,会员不贵,但体验实在是太割裂了。只能去特定平台才能看到特定的东西,对于视频其实还好,切一个app,但是音乐咧,我只想随机我所有的歌,我没法把几个平台的歌放在一起随机。
总之,作为正版流媒体平台的受害者,我选择离开流媒体平台,支持正版的方式有非常的多,比方说买专辑,买光碟,但是,我需要一个允许我在任何地方在线播放的平台。
所以,我需要一个NAS。
但显然不够,作为一个coding玩家,我还需要一个开发环境,我需要一个运行环境等等等等
所以,All In One,好巧不巧,我家有公网IP,而我又有域名,Cloudflare又可以白嫖DDNS,走起~
平台和硬件选择
低功耗 or 高性能
确定了要AIO,那自然需要考虑一个严重的问题,传统NAS上肯定是追求低功耗的,并且不要求多高的性能,树莓派都可以胜任,甚至还有路由器刷op挂一个samba直接用的。
当然了,NAS其实还有很多现成的方案,群晖啊,威联通啊什么的,而硬件上,也有之前的矿机什么星际蜗牛啊,最早的J1900到后来的J3455,可以说是五花八门了。
不过都有一个共同特点,恰好都不是我现在入手能捞到实惠的东西,车那是一去不复返,鱼塘全涨价了。
还有一个很重要的点,我不打算花很多钱,我预算1000以内弄完除硬盘以外的东西,然后花500左右整硬盘。
并且我需要足够高的性能,J1900这些是不太行了,J3455绝对就超预算了。
最后选择了闻名江湖的E5神教!
配置单
|
|
除掉硬盘,算上邮费,总共花了750,邮费就84了, 两块HGST,赶上了涨价,花了454, 所以总共1204,还可以吧,预算内
这一套下来满载上200W了,不过考虑到大部分时间是基本上空载的,当然算不上省电,根据网友的测试,空载不到20W,一个月十几块钱电费吧(-_-
系统和软件
一般人就是直接黑群晖了,但咱是一般人嘛,咱是折腾佬啊
想都没想就是手搓KVM虚拟化
,从此踩坑无数后续章节慢慢补坑
正片
一、Arch物理系统安装
首先贴上Arch的官方wiki的中文安装文档
好了,本章完结
以下注意事项
- fdisk工具不支持gpt格式,也不支持2T以上容量的分区操作,所以我建议用
parted
代替,当然这个工具也是安装在Arch的livecd里了 /etc/locale.gen
文件一定要编辑,然后用locale-gen
生成信息,并且在/etc/locale.conf
文件中至少写上LANG=en_US.UTF-8
,否则将无法在终端显示中文,即使你安装了中文字体- 在重启到安装好的系统之前,网络工具一定要装,这里推荐一下
networkmanager
,安装命令sudo pacman -Sy networkmanager
,然后设置开机启动sudo systemctl enable NetworkManager
- 安装好系统之后,文档里有简单的提了一下安装引导的事情,如果你不想开不了机,就记得点一下
GRUB
进去看一下关于引导的安装 - 包管理器我建议使用
yay
而不是pacman
,它们的命令是基本上一样的,但yay
支持从archlinuxcn
和AUR
下载软件包,这显然比pacman
更方便,以下的命令我将使用yay
而不是pacman
因为AIO服务器的重点并不在物理机的系统安装上,而且网上有太多的同类教程可供参考,所以我就略过了,只标注了我认为需要注意一下的东西
二、KVM虚拟化
安装好物理机之后,接下来就是虚拟化,显然现在有非常多的懒人解决方案,集成度非常的高,效果也不错,有基于Debian的各种系统,也有不基于任何平台的单纯WEB管理的各种虚拟化管理页面,but,本着不对外提供服务的东西不需要可视化界面的原则,以及对KVM虚拟化的好奇,我不使用各种WEB或GUI管理工具。
同样,我会在开头,将ArchWiki的文档放在这里,使用Arch的好处就是相当完善的文档,并且中文支持不错,当然我还是建议尽可能的查看英文文档,毕竟更新及时.
检查虚拟化支持
纯软件虚拟化不是不行但是效率实在实在太低了,所以现在都是从硬件平台上就开始支持各种虚拟化技术,也就是说,你需要先在主板的BIOS上打开虚拟化的开关,然后在系统里确认对虚拟化的支持状态。
在终端执行
LC_ALL=C lscpu | grep Virtualization
或grep -E --color=auto 'vmx|svm|0xc0f' /proc/cpuinfo
,输出什么东西并不是太重要,重要的是不能没有输出,如果没有任何东西输出的话,你就需要去主板检查一下bios是不是没有正确打开虚拟化的开关在确定了硬件支持之后,就需要确定软件是否安装了,执行
zgrep CONFIG_KVM /proc/config.gz
查看Linux内核的虚拟化模块是否安装,如果输出的结果不是y
或者m
,则说明虚拟化模块没有安装到位。因为我没有遇到这个问题,所以我只能将安装模块的文档放在这里,如果你遇到了,请自行解决之后需要确定内核模块是否已经加载,执行
lsmod | grep kvm
,如果执行了之后没有输出东西,但是上一步又确定了已经安装模块,那就需要手动加载。同样的,我也没有遇到这个问题
到这里就差不多了,当然还有其他的东西可以使用,比方说VIRTIO
模块、嵌套虚拟化之类的东西,可以参考上面的文档自行检查。
安装软件包
在Arch安装软件一直都是一件轻松愉快的事情,archlinuxcn也好AUR也好,可谓是独步天下
不过我这里需要说明的事情是,KVM是一种虚拟化技术,而不是一个虚拟机,我们需要一个虚拟机来应用这种技术,在Linux平台上,那自然是QEMU
了
同样,文档就放在这了
因为我不启用GUI
,也就是不安装桌面,所以我不需要对图形化的支持,在安装qemu
的时候我选择qemu-headless
,如果你有图形化的需求,则安装qemu
安装命令yay -Sy qemu-headless
QEMU
简单跑个win虚拟机
运行Windows虚拟机跟直接跑Linux虚拟机不太一样,所以我单独列了一个小节,如果你不打算运行Windows虚拟机,那可以跳过,注意,本小节旨在将Windows虚拟机运行并完成安装,不会涉及到显卡直通或虚拟化显卡的内容
准备文件
因为微软❤️开源,所以我们没法直接在qemu虚拟机上启动Windows的镜像,我们需要一个辅助镜像virtio-win,Arch可以直接通过包管理下载到,执行命令
yay -Sy virtio-win
,然后这个镜像会被下载到/var/lib/libvirt/images/virtio-win.iso
,将它复制到跟我们Windows系统镜像一个目录下就行了。下载Windows的系统镜像,比方说我下载的镜像重命名为
win10_2004.iso
。主要是原来的名字太长了现在启动镜像和系统镜像都有了,我需要创建一个虚拟磁盘,就像装物理机的系统需要一块硬盘一样,虚拟机一样需要能识别到一个磁盘空间,执行命令
qemu-img create -f qcow2 win10.qcow2 100G
,这里我创建了一个叫win10.qcow2
的镜像文件,镜像格式是qcow2
,容量大小是100G,不过不用担心你的物理空间没那么大,它不会直接占用100G的空间,是动态占用的,不过你依然至少保留20G的空闲空间。
至此,我们必要的文件就已经准备好了
启动win10虚拟机
qemu
跟VMWare和VBox那些不一样,它不具备管理和持久化虚拟机的能力,你需要手动配置每一个参数,然后以命令的形式运行,运行之后不会保存参数,你下次运行依旧需要输入那些参数,所以我们创建一个shell
文件来运行,省得敲那么长的命令
并且我们不直接使用qemu
命令,因为qemu软件包已经提供了一个不同架构的命令,比方说我们跑64位x86的虚拟机就用qemu-system-x86_64
。用这个已经很繁琐了,就不用更繁琐的qemu
了
执行vim win.sh
然后复制下面的东西
|
|
别忘了把文件名和路径换成你们自己的,还有一些参数,比方说
-smp 20
是20核,建议改成你的电脑的真实配置,包括-m 8G
是虚拟机分配的8G内存
然后给它执行权限chmod +x win.sh
,再运行它就可以启动了,但是因为我们没有图形化,看不到启动,这就需要我们从其他电脑远程了,上面的脚本里我使用了spice
来做远程,自行从互联网下载一个支持连接spice
的客户端连接即可。
剩下的事情就是正常的安装和重启,就可以看到一个非常卡的win10虚拟机在跑了
Libvirt 管理KVM
qemu
非常的强但是不好用,所以我们需要一个能像正常虚拟机一样管理它的,这里就不得不提libvirt
,它提供了一些C实现的后端接口,和一个能用的前端virsh
安装软件包
安装依旧很简单,只需要执行yay -Sy libvirt
,但是只有这个是不够的,不同于上面小节中简单的启动一个虚拟机,我们需要管理一些东西,比方说网络,所以我们还需要一些其他的东西
执行 yay -Sy libvirt bridge-utils dnsmasq
启动服务
libvirt
是一个常驻服务,所以需要启动,执行sudo systemctl start libvirtd
,不过这样每次都需要手动启动,执行sudo systemctl enable libvirtd
实现开机自启
同时,我们需要启动virsh自带的NAT网络,执行sudo virsh net-start default
可以执行sudo virsh net-list --all
查看网络是否启动了,如果有一个defalut
网络那就是启动了
使用原生virsh启动虚拟机
创建win10.xml
文件,复制下面的内容,修改之后,执行virsh define win10.xml
可以增加一个虚拟机,并且受virsh
管理。
|
|
虽然这是核心玩法,但是手写xml文件真的太麻烦了,而且参数实在太多了,所以还是需要一个东西,能帮我们手动生成一些模板配置,只需要在这个基础上简单修改我们的参数,这就是
virt-install
了。
安装virt-install
一样直接安装即可yay -Sy virt-install
安装这东西让我纠结了非常久,因为我本来是不想在物理机上装任何执行环境,哪怕是Python,但是手写xml真的太麻烦了……这之间我发现了有另一个
libvirt-go
的项目,我在想如果有一个virt-install-go
的项目就好了,这样不需要依赖也能直接用,不过目前是没有的,虽然可以自己实现,我自己稍微写了一下,这个周期实在太长了,而且libvirt-go
本身也还有问题,文档也非常的缺,只能先用virt-install
这个py的版本了……
使用virt-install
创建win10虚拟机
执行
|
|
然后就可以用spice
连接过去看了,本地的窗口运行可以Ctrl+C
关闭了
virsh
管理虚拟机
注意: virsh命令不需要root权限
- 查看虚拟机列表:
virsh list --all
- 关闭虚拟机(不删除):
virsh destroy name
- 删除虚拟机(不关闭):
virsh undefine name
- 设置虚拟机开机自启:
virsh autostart name
- 取消虚拟机开机自启:
virsh autostart --disable name
如果你的虚拟机正在运行,没有先执行关闭就执行了删除,虚拟机不会被马上删除,会等到关闭之后才删除