我从 eBay 购买了一张 64 GB 的 SD 卡。当我将 Arch Linux ARM 映像刻录到该卡上并使用它启动我的 Raspberry Pi 时,它运行正常。
但是,当我尝试在其上创建单个 ext4 分区以使用卡的所有容量时,会出现错误。mkfs.ext4
总是顺利完成;但是,无法编辑分区mount
,总是抛出错误并dmesg
显示内核消息包括Cannot find journal
。至少在两个平台上已经证明是这种情况:Arch Linux ARM 和 Ubuntu 13.04。
另一方面,我可以创建和安装 FAT32 分区而不会出现错误(尚未进行完整容量检查)。
我听说有些坏人可以更改 SD 卡接口,向操作系统报告错误的容量(即该卡实际上只有 2 GB,但它报告自己为 64 GB),以便以更高的价格出售该卡。
我知道有类似工具badblocks
可以帮我检查 SD 卡是否有坏块。可以badblocks
检测出这样的问题吗?如果不行,还有哪些其他解决方案可以让我测试卡?
我最想知道我是否被骗了;如果结果显示我收到了一件坏货,我只能退回给卖家,而不是向 eBay 报告有人试图欺骗我。
更新
操作和消息:
~$ sudo mkfs.ext4 /dev/sde1
mke2fs 1.42.5 (29-Jul-2012)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
4096000 inodes, 16383996 blocks
819199 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
500 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
~$ dmesg | tail
...
[4199.749118]...
~$ sudo mount /dev/sde1 /mnt
mount: wrong fs type, bad option, bad superblock on /dev/sde1,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so
~$ dmesg | tail
...
[ 4199.749118]...
[ 4460.857603] JBD2: no valid journal superblock found
[ 4460.857618] EXT4-fs (sde1): error loading journal
更新
我运行了,badblocks /dev/sde
但是没有报错,也就是说剩下的原因是:
SD 车很好,但由于某种原因
mke2fs
或mount
内核有一个导致问题的错误。我被骗了,但
badblocks
无法检测到失败。这是合理的,因为我认为badblocks
只是进行了一些就地写入读取测试。但是,作弊者可以将对出站区域的访问链接回某个入站块。在这种情况下,就地写入读取检查无法检测到问题。
如果没有应用程序可以进行适当的测试,我想我可以尝试编写一个简单的 C 程序来测试它。
答案1
答案2
现已通过以下步骤确认了作弊行为:
生成一个随机数据文件。(4194304 = 4 × 1024 × 1024 = 4 MiB,总大小 = 40 × 4 MiB = 160 MiB)
命令:
dd if=/dev/urandom of=test.orig bs=4194304 count=40 40+0 records in 40+0 records out 167772160 bytes (168 MB) copied, 11.0518 s, 15.2 MB/s
将数据复制到 SD 卡。(2038340 × 4096 = 8153600 KiB = 7962.5 MiB)
命令:
sudo dd if=test.orig of=/dev/sde seek=2038399 bs=4096 40960+0 records in 40960+0 records out 167772160 bytes (168 MB) copied, 41.6087 s, 4.0 MB/s
从 SD 卡读回数据。
命令:
sudo dd if=/dev/sde of=test.result skip=2038399 bs=4096 count=40960 40960+0 records in 40960+0 records out 167772160 bytes (168 MB) copied, 14.5498 s, 11.5 MB/s
显示结果
命令:
hexdump test.result | less ... 0000ff0 b006 fe69 0823 a635 084a f30a c2db 3f19 0001000 0000 0000 0000 0000 0000 0000 0000 0000 * 1a81000 a8a5 9f9d 6722 7f45 fbde 514c fecd 5145 ...
发生了什么?我们观察到零间隙。这表明随机数据尚未实际写入卡中。但为什么数据会在之后返回1a81000
?显然卡有一个内部缓存。
我们还可以尝试调查缓存的行为。
hexdump test.orig | grep ' 0000 0000 '
没有结果,这意味着产生的垃圾没有这样的模式。然而,
hexdump test.result | grep ' 0000 0000 '
0001000 0000 0000 0000 0000 0000 0000 0000 0000
213b000 0000 0000 0000 0000 0000 0000 0000 0000
407b000 0000 0000 0000 0000 0000 0000 0000 0000
601b000 0000 0000 0000 0000 0000 0000 0000 0000
有 4 场比赛。
所以这就是它通过badblocks
检查的原因。进一步的测试可以显示,实际容量为 7962.5 MB,略小于 8 GB。
我得出的结论是,这不太可能只是随机的硬件故障,而更有可能是一种欺骗行为(即欺诈)。我想知道我可以采取什么措施来帮助其他受害者。
更新 11/05/2019
人们问我如何确定正确的
seek
参数2038399
。我的经验比上面展示的要多得多。基本上,你首先必须猜测。你必须猜测一个合适的数据大小,你必须猜测数据损坏的位置。但你总是可以使用二分法帮助。在下面的评论中,我认为我假设上面的第二步(将数据复制到 SD 卡)只复制 1 个扇区。但我在实验中没有犯这个错误。相反,是为了
seek
表明在“显示结果”步骤中,偏移量1000
只是发生在数据的第二个扇区中。如果seek
是 2038399 个扇区,则损坏发生在第 2038400 个扇区。
答案3
首先,阅读F3@Radtoo 的回答。这是正确的方法。
我不知怎么地错过了它,并尝试了我自己的办法:
创建 1GB 测试文件:
dd if=/dev/urandom bs=1024k count=1024 of=testfile1gb
将该文件的副本写入 SD 卡(64 是 SD 卡大小,单位为 GB):
for i in $(seq 1 64); do dd if=testfile1gb bs=1024k of=/media/sdb1/test.$i; done
检查文件的 md5(除最后一个不完整文件外,其他文件均应匹配):
md5sum testfile1gb /media/sdb1/test.*
答案4
我编写了一个小脚本,执行以下操作。
-为目标 USB 或 SC 卡创建临时目录
-创建一个带有 md5sum 校验和的 5MB 随机生成的参考文件 -将参考文件复制到目标并从目标生成 md5sum 校验以确认读/写成功 - 将目标填充至容量(100%)或在发生校验和错误时停止 - 一旦脚本自然停止,它就会显示目标报告的大小、已使用和可用的数量。通过这个脚本,我得出结论,我被一个 eBay 卖家欺骗了,他把 8GB 的 microSD 换成了 64GB
#!/bin/bash
#Save file as 'filltext' and remember to set the executable flag to run it
if [ -d "$1" ]; then
if [ -d "$1/tmp" ]; then
echo "."
else
mkdir $1/tmp
fi
#Make a tmp file and fill it with 3MB of junk
TMPTSTR=$(mktemp)
base64 </dev/urandom | head -c 5000000 > $TMPTSTR
TESTVAL=$(md5sum $TMPTSTR | awk '{ print $1 }')
while $CHECKEDOK; do
FL=$( tr -dc A-Za-z0-9 </dev/urandom | head -c 5).TEST
cp $TMPTSTR $1/tmp/$FL
TESTTMP=$(md5sum $1/tmp/$FL | awk '{ print $1 }')
if [ "$TESTVAL" != "$TESTTMP" ]; then
echo "Checksum ERROR"
echo "Original: $TESTVAL Temp File:$TESTTMP"
CHECKEDOK=false
df $1 -Ph
echo
echo
echo "Removing test files"
rm $1/tmp -r
rm $TMPTSTR
df $1 -Ph
else
#echo -n "$FL..."
clear
df $1 -Ph
fi
done
else
echo "Error: Directory $1 does not exists."
echo "Usage: filltest [PATH]"
echo
echo "Try the PATH of a mounted USB dongle or SD card to confirm it's capacity"
fi