5
21
2016
16

当 SSD 坏掉之后

某天,我注意到系统日志中有如下报错:

ata2.00: exception Emask 0x0 SAct 0x80 SErr 0x0 action 0x0
ata2.00: irq_stat 0x40000008
ata2.00: failed command: READ FPDMA QUEUED
ata2.00: cmd 60/18:38:64:ad:96/00:00:00:00:00/40 tag 7 ncq 12288 in
         res 41/40:00:64:ad:96/00:00:00:00:00/00 Emask 0x409 (media error) <F>
ata2.00: status: { DRDY ERR }
ata2.00: error: { UNC }
ata2.00: configured for UDMA/133
sd 1:0:0:0: [sdb] tag#7 UNKNOWN(0x2003) Result: hostbyte=0x00 driverbyte=0x08
sd 1:0:0:0: [sdb] tag#7 Sense Key : 0x3 [current] [descriptor] 
sd 1:0:0:0: [sdb] tag#7 ASC=0x11 ASCQ=0x4 
sd 1:0:0:0: [sdb] tag#7 CDB: opcode=0x28 28 00 00 96 ad 64 00 00 18 00
blk_update_request: I/O error, dev sdb, sector 9874788
bcache: bch_count_io_errors() sdb1: IO error on reading dirty data from cache, recovering
ata2: EH complete

啊,看来我的 SSD 要坏掉了么?!拿 bcache-status 看了一下状态,已经500多个报错了,但是我并没有遇到什么问题。看了一下 SSD 的 SMART 信息,也是500多个报错。这种报错出现已经有几天了,但是似乎影响并不大?SMART 报告也说「状况正常」。那就等有时间再处理好了,先把 bcache 缓存策略从「writeback」改成「writethrough」好了。我当时是这么想的。

出事的 SSD 是笔记本自带的,16G,被我用作缓存了。使用的是 bcache,一年之前我写文章讲过的。没想到刚刚一年,就开始出问题了。

过了一两天之后。我正上班中,同步 MediaWiki 数据时发现自己的机器又连不上了。我起初以为是网络问题,因为我记得很清楚我的机器是开着的。但是过了一会儿它还是不能访问。我 ping 了一下,却发现是通的!登陆到我作为路由器的树莓派上却发现,网络是正常的。能 ping 通笔记本,但是从树莓派上也 ssh 不了,访问 nginx 也没回应。所以笔记本还在线,但是系统出问题了。奇怪的是,访问另一端口上我用 Tornado 写的 Web 程序时却是正常的。

终于等到了下班。回到家里之后就听见笔记本风扇呼呼地响着。赶紧打开查看。htop 显示 journald 正在使用 CPU。于是去看 journald 日志,心里顿时凉了半截:日志只记录到上午,但满是上边那样的 SSD 报错。进一步的检查发现,/ 分区已经被挂载为只读,syslog-ng 日志比 journald 日志记录了更多的报错。火狐已经不知道什么时候挂掉了,并且启动不了。sudo 还是好的,但是运行 zsh 时会段错误。运行 bash 的话,会报一点错,可以看到有些文件已经变成无意义的数据了。bash 能启动,但是很奇怪的是,输入不了字符 e……想起还装了 dash,于是用这个连最基本的补全都没有的 shell,配合还没有挂掉的连着 VPS 的 mosh 上的 IRC 上网友们的帮助,尝试禁用 SSD 缓存。

结果是失败了。关于 bcache 有些资料与我看到的情况并不一致。重启会报一些错,然后我进入了 initramfs 里的 shell,尝试禁用 SSD,依旧失败中,脏数据写不回去,所以禁用不了缓存……不过看到了缓存中脏数据只有几百K。当然单位是什么我就不知道了……

放弃。又一天,我改从救援系统进入。记得有个工具能把普通分区转成 bcache。手机上网找到了,blocks。但是它并不能把 bcache 转回来。好在是开源项目,我读了一下代码,结合别人的说法,结论是:把普通分区转为 bcache,只要把分区缩小,在起始处空出一点空间,然后写入 bcache 的超级块就可以了。于是反过来,只要跳过 bcache 的超级块来读,就可以读到原来的分区数据了。

但是,bcache 超级块有多大呢?不知道。不过之前看到过一个扫数据的脚本,用类似的办法找一下分区数据的位置好了:

for i in {1..20}; do dd if=/dev/sda2 skip=$i | file -; done

file 显示在第8块的地方发现了「LUKS encrypted file」。这就是我要找的文件系统了!

为保险起见,先读读看。使用 losetup 把 /dev/sda2 映射成只读的 loop 设备,但是跳过开头的 8192 字节(dd 的块是 512 字节一个)。然后用 cryptsetup 解密。解密成功了。只读挂载解密之后的 ext4 文件系统。挂载成功了。看了一下内核日志,没有报错,没有警告。chroot 进去,正常,没有段错误,配置文件没有变成无意义的乱码。一切进行得好顺利!损坏程度比我以为的要轻不少呢!

为了确认损坏情况,我进行了一次模拟备份,也就是 rsync 的「--dry-run」选项。这样与最近的一次备份作比较,看看差异。结果很乐观,rsync 只报了十来个 I/O 错误。不过这也说明文件系统还是有问题的。

又一天。开始恢复系统了。还是从救援系统进入。进入 gdisk,删除原来的 sda2 分区,新建一个小了 8192 字节的分区。经验表明这样子删掉再重建分区表是没有问题的。也确实没出什么问题。不带 bcache 的文件系统出来了。解密之,然后使用 fsck 修复。修复过程中,fsck 问了我一大堆是不是要修复的问题。修复完毕之后,更改内核选项以便适应新的分区表,重启。

一切正常。不过根据之前 rsync 和修复过程中提到的文件名,去看了一下那些文件。都是最近更新系统时的一些 Python 文件。有一些文件消失了,另一些文件的权限和类型变得很奇怪。删掉,重装安装对应的软件包。完事了~不过没有了 SSD 缓存,能够感觉到有些操作会慢不少。

这 SSD 也真容易坏啊。刚刚一年呢。而且坏的过程很快,预警期只有几天。现在 SMART 报告已经出现过1000多个错误了,但整体评估还是「磁盘状况正常」……

好在我用的都是自由软件,虽然可能找遍整个互联网都没有个说法,但是还有实现它们的源码可以阅读,可以自己去思考解决方案。当然啦,就算这个 bcache 完全坏掉了,我也不需要太惊慌,因为我有备份嘛,更麻烦,但最多只损失几天的数据,不会突然之间什么都没有了。

Category: Linux | Tags: linux 数据恢复 bcache
5
11
2015
12

使用 bcache 自制「混合硬盘」

换了新本子,外存是1T机械硬盘和16G固态硬盘。这16G SSD 速度挺快的尤其是读的时候,可它拿来放 / 都不够呢,于是拿来作缓存加速。根据局部性原理,虽然数据很多,但是最常访问的只占其中一小部分呢。

搜索的结果是有三个方案:bcache、dm-cache 和 Facebook 的 flashcache。前两者在官方内核里,不需要另外安装。我是最先在 Arch Wiki 上看到 bcache 的,后来又看 dm-cache,发现需要自己指定元数组的存储什么的,略复杂。而且一些评测显示 bcache 性能要好一点,所以就它了。

$$ \require{extpfeil} \rm{SSD} + \rm{HDD} \xlongequal{\rm bcache} \rm{SSHD} $$

配置起来其实很简单。首先安装 AUR 里的 bcache-tools,然后创建存储数据的分区和用于缓存的分区:

make-bcache -B /dev/sda2
make-bcache -C /dev/sdb1

教程上使用的是 SSD 的分区。换成 SSD 的块设备本身应该也可以。

参数什么的我没调。然后是把缓存设备的 UUID 写到 /sys/block/bcache0/bcache/attach 里。

为了最优性能,往 /sys/block/bcache0/bcache/cache_mode 里写入「writeback」来更改其缓存策略为「写回」。默认是「写通」(writethrough),也就是写的时候同时写缓存和后端设备,不会在缓存出问题时丢数据,但是会慢。另一个可选的策略是「writearound」,不知道该怎么译,是只写到后端设备而不写缓存的。最后一个是「none」,不知道用了它会发生什么……

换出策略使用默认的 LRU(最近最少使用)。剩下的两个(FIFO 和随机)应该效果没 LRU 好。

这些设备是会记住的,无需在启动时重启配置。至少我用的 4.0.1 内核是这样。

弄好之后就可以折腾 /dev/bcache0 这个块设备了。我放弃了之前使用文件级的 eCryptfs,改用在备份里使用得挺爽的块设备级的 dm-crypt,然后才格式化成 ext4。也就是:

$$ 文件数据 \xrightarrow{\textrm{I/O相关系统调用}} \rm{ext4} \xrightarrow{加密} \textrm{dm-crypt} \xrightarrow{缓存} \rm{bcache} \xrightarrow{写入} \rm{SSD} + \rm{HDD} $$

所以我的 /etc/mkinitcpio.conf 里要加上 bcache 和 encrypt 两个 hook:

HOOKS="base udev autodetect modconf block bcache encrypt filesystems keyboard fsck resume"

(不过这样子不能用外接 USB 键盘输入密码的。)

然后 mkinitcpio -p linux 一下,生成新的 initramfs 镜像。

为了共享缓存,我把 / 和 /home 放一起了(不过我猜对 /dev/bcache0 进行分区也是可以的?)。虽然这样子整个 / 用去了60多G空间,但是缓存的命中率还是非常高的——

>>> bcache-status -a
--- bcache ---
Device                      /dev/bcache0 (254:0)
UUID                        07a9b6a5-7f18-4950-84d6-c90abaaf65dc
Block Size                  0.50KiB
Bucket Size                 512.00KiB
Congested?                  False
Read Congestion             2.0ms
Write Congestion            20.0ms
Total Cache Size            14.91GiB
Total Cache Used            14.91GiB    (100%)
Total Cache Unused          0B  (0%)
Dirty Data                  0.50KiB     (0%)
Evictable Cache             14.17GiB    (95%)
Replacement Policy          [lru] fifo random
Cache Mode                  writethrough [writeback] writearound none
Last 5min Hits              439 (92%)
Last 5min Misses            38
Last 5min Bypass Hits       424 (100%)
Last 5min Bypass Misses     0
Last 5min Bypassed          61.50MiB
Last Hour Hits              46003       (88%)
Last Hour Misses            6051
Last Hour Bypass Hits       94043       (100%)
Last Hour Bypass Misses     0
Last Hour Bypassed          400.00MiB
Last Day Hits               79485       (88%)
Last Day Misses             10214
Last Day Bypass Hits        170383      (100%)
Last Day Bypass Misses      0
Last Day Bypassed           602.00MiB
Total Hits                  79485       (88%)
Total Misses                10214
Total Bypass Hits           170383      (100%)
Total Bypass Misses         0
Total Bypassed              602.00MiB

bcache-status 脚本来自这里

感觉还挺快的,特别是各种程序如火狐、gvim、pidgin、zsh 的启动速度,以及 mlocate、pacman 的搜索速度都非常快。没有对比数据,因为我没有试过在这个本子上不用 bcache 的情况下把系统弄起来。之前的旧本子可能因为分区太满导致碎片严重,所以 I/O 性能很差劲的。

Category: Linux | Tags: linux Arch Linux bcache

部分静态文件存储由又拍云存储提供。 | Theme: Aeros 2.0 by TheBuckmaker.com