我的 SSD 出现了某种硬件故障,我可以对其进行 rma,因为它仍在保修期内,但他们的服务不包括数据恢复。我已经从中收集了我的工作文件,但我的个人文件和插件仍然存在,我想恢复它们。
问题是……带宽和总副本大小似乎是一个问题。读太多,驱动器就会崩溃。报告到处都有坏扇区(错误)或关闭整个操作系统。因此,我已将驱动器放入外壳中,以便可以热插拔它,因为我怀疑内存缓冲区是问题所在。我考虑按照此处的另一个问题使用带有带宽限制的 rsync,但我相信我需要错开复制过程以使缓冲区自行清除或冷却。
我需要一些脚本或工具来恢复丢失的数据。
答案1
到处报告坏扇区(错误)
SSD 上不存在“扇区”。 “块”确实如此,如果您的驱动器将它们报告为坏,那就意味着,因为没有什么可以机械地失败:
- 断言地址线以获取块的这些位
- 读出存储单元,这意味着“获得了电压读出向量”
- 尝试通过对它们应用相当复杂的软输入纠错码将它们转换为位
- 返回(成功和数据)或(错误):
- 当尝试解码它们(迭代)成功时,会产生一个错误项(解码器中的“综合症”),该错误项在某个时刻为零
- 当软值实际上从未被修改和纠错以产生没有错误的单词时,会出现错误
所以,你会得到一个错误。这意味着该内容无法读出。不存在“SSD 是错误的关于数据不可恢复”:它总是读取一些电压,无论一切有多么损坏,并检查这些是否通过检查,并在必要时纠正它们,和可能的。
所以:
到处报告坏扇区
你必须相信你的SSD——它实际上无法读取数据。尽管存储单元(顺便说一句,是充电到某个电压的小电容器)完好无损,但您可以更改为“全局”的唯一事情是,如果您“移动”转换模拟的 ADC 的参考电压,则使阅读变得困难电压到数字值。然后,即使实际内存正常,您的解码器也会得到不正确的软输入。
但这个电压是产生的在同一个模具内因为 ADC(在您的闪存芯片内)应该对电源电压等变化具有很强的弹性。
所以,也许这确实是一个热问题,或者是某种硅模式故障。
无论哪种方式,在我看来,您都不想使用 rsync 或任何文件系统级工具来从驱动器获取数据。这要求操作系统能够非常频繁地访问相同的数据点,只是为了了解哪个文件中有哪些数据。
您需要做的是进行块设备级别的复制,并分小步进行。将(例如)16 MB 读入图像文件。稍等片刻。阅读 16 MB...等等。
这可以在 ZSH/bash shell 脚本中通过一个循环来完成,该循环使用 依次读取这些块dd
,然后调用sleep
wait,然后读取下一个等等,或者在几行 Python 中完成。不要忘记检查读取过程中是否有错误,并在发生错误时中止该过程,以便稍后在同一点重新启动它。
因为需要实际准备的解决方案:
#!/usr/bin/zsh
# Copyright 2022 Marcus Müller
# SPDX-License-Identifier: BSD-3-Clause
# Find the license text under https://spdx.org/licenses/BSD-3-Clause.html
# THIS SCRIPT IS UNTESTED AND COMES WITH NO WARRANTIES, FOLKS.
IN_DEVICE=/dev/yoursource_ssd
BACKUP_IMG=myimage
LOGFILE=broken_mbs.txt
# get size, round up to full MB
size_in_bytes=$(blockdev "${IN_DEVICE}")
size_in_MB=$(( ( ${size_in_bytes} + 2**20 - 1) / 2**20 ))
#check whether size > 0
if [[ ! ${size_in_MB} -gt 0 ]]; then
logger -p user.crit "Nope, can't determine size of ${IN_DEVICE}. I'm outta here."
echo "Failure on input" >&2
exit -1
else
logger -p user.info "Trying to back up ${IN_DEVICE}, size ${size_in_MB} MB"
fi
if fallocate -l "${size_in_MB}MiB" "${BACKUP_IMG}" ; then
logger -p user.info "preallocated ${BACKUP_IMG}"
else
logger -p user.crit "failed to preallocate ${BACKUP_IMG}"
echo "failure on output" >&2
exit -2
fi
failcounter=0
MB=$((2**20))
for i in {0..$((${size_in_MB}-1))}; do
if \
dd \
"if=${IN_DEVICE}" \
"of=${BACKUP_IMG}" \
"ibs=${MB}" "obs=${MB}" \
"skip=${i}" "seek=${i}" ; \
then
echo "backed up MB nr. ${i}"
else
failcounter=$(( ${failcounter} + 1 ))
echo "${failcounter}. error: couldn't backup MB nr. $i" > &2
echo "${i}" >> ${LOGFILE}
logger -p user.err "couldn't backup MB nr. $i"
fi
sleep 0.5
done
echo "Got ${failcounter} failures"
exit ${failcounter}