SVX日記
2017-06-14(Wed) 世にも奇妙なmicroSD
先日、某サイトから、安価な16GBのmicroSDカードを購入した。さほど、厳格に用途を決めていたわけではないし、とりあえず工作中のmp3プレイヤにでも使ってみようと、Windows10マシンでFAT32フォーマットし、Linuxマシンからmp3ファイル、flacファイルを書き込み、mp3プレイヤに挿し込んだ。
LinuxマシンでFATを扱ったことがマズいのかしらん? と、思い、ファイルの書き込みまでWindows10マシンで完結させても、やっぱりおかしな症状が出る。いろいろと試してみると、microSDカードを挿して、書いて、抜いて、挿すと、もう、書いた内容がおかしくなっている。これ、microSDカードがおかしいんやないか?
以前に「抜くと元に戻るSDカード」を経験して以来「ここ一番にはSanDisk」を励行してきたのだが、それを外した途端にトラブるもんかねぇ。
購入元に連絡したところ、即座に代品を送ってくれ、翌日には代品が手元に届くという素晴らしい対応だった。んが、不良品を返送する前に、再テストしてみたところ、なんと、代品にも同じ現象が出てしまった。どうも、ある程度の容量を書き込むと、microSDを抜き差しせずとも、先頭部分がブッ壊れるっぽい。
と、ここでピンときた。以前に、見た目はxxGBなのに、実際にはxxGBの容量を持たない詐欺的なSDカードがあると聞いたことがある。改めて考えれば、一定の場所でループ構造にしている、つまり、上位ビットを捨てることで実現している、と考えるのが妥当なわけで、そうであれば今回の事象に合致する。
#!/usr/bin/env ruby
# SD カードチェッカ
class Integer
def to_h
sprintf('%d', self).to_s.reverse.scan(/.{1,3}/).join(',').reverse
end
end
dev = ARGV[0]
check_max = 8 * 1024 * 1024 * 1024 # 8Gbytes
puts('device = %s, check_max = %16s' % [dev, check_max.to_h])
adr = 0; open(dev, 'w') {|fh|
last_md5 = nil; while(adr < check_max)
puts('%16s .. ' % adr.to_h)
chunk = ''; (1024 * 1024 / 8).times { # 1Mbytes
chunk << [adr >> 32, adr & 0xFFFFFFFF].pack('N*'); adr += 8
}
fh.write(chunk)
fh.fsync
system('dd if=%s of=/tmp/_sdcard_checker_ bs=4096 count=1 iflag=direct >/dev/null 2>&1' % dev)
md5 = `md5sum /tmp/_sdcard_checker_`.split(/\s/)[0]
puts(' %s %s' % [md5, last_md5])
last_md5 and last_md5 != md5 and raise('Unmatch!')
last_md5 = md5
end
}
puts('%16s finished.' % adr.to_h)
__END__
# sdcard_checker /dev/sdb
device = /dev/sdb, check_max = 8,589,934,592
0 ..
fa9971f35ad33faaaf100800b4b85b8c
1,048,576 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
2,097,152 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
3,145,728 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
4,194,304 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
:
:
:
1,609,564,160 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
1,610,612,736 ..
fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
:
:
:
それならばと、プログラムを変更してみた。今度は、同じようにデバイスの先頭からシーケンシャル番号で領域を書きツブしながらも、先頭部分だけでなく、書きツブした部分をトビトビに監視する、というものだ。イザ、実行ッ!
#!/usr/bin/env ruby
# SD カードチェッカ 2
class Integer
def to_h
sprintf('%d', self).to_s.reverse.scan(/.{1,3}/).join(',').reverse
end
end
dev = ARGV[0]
check_max = 8 * 1024 * 1024 * 1024 # 8Gbytes
#check_step = 128 * 1024 * 1024 # 128Mbytes
check_step = 63 * 1024 * 1024 # 63Mbytes
puts('device = %s, check_max = %16s' % [dev, check_max.to_h])
adr = 0; open(dev, 'w') {|fh|
check_md5s = {}; while(adr < check_max)
puts('%16s .. ' % adr.to_h)
chunk = ''; (1024 * 1024 / 8).times { # 1Mbytes
chunk << [adr >> 32, adr & 0xFFFFFFFF].pack('N*'); adr += 8
}
fh.write(chunk)
fh.fsync
check_adr = 0; while(check_adr < adr)
system('dd if=%s of=/tmp/_sdcard_checker_ bs=4096 count=1 skip=%d iflag=direct >/dev/null 2>&1' % [dev, check_adr >> 12])
md5 = `md5sum /tmp/_sdcard_checker_`.split(/\s/)[0]
check_md5s[check_adr] ||= md5
puts('%16s %16s %s %s' % [check_adr.to_h, check_adr >> 12, md5, check_md5s[check_adr]])
check_md5s[check_adr] != md5 and raise('Unmatch!')
check_adr += check_step
end
end
}
puts('%16s finished.' % adr.to_h)
__END__
# sdcard_checker2 /dev/sdb
device = /dev/sdb, check_max = 8,589,934,592
0 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
1,048,576 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
2,097,152 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
3,145,728 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
4,194,304 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
:
:
:
267,386,880 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
134,217,728 32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
268,435,456 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
134,217,728 32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
268,435,456 65536 ba2930882b4da3d3ddd5b8697fc127d5 ba2930882b4da3d3ddd5b8697fc127d5
269,484,032 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
134,217,728 32768 01517d88da540a8eb5d44af02f122649 01517d88da540a8eb5d44af02f122649
268,435,456 65536 5aa7b9d34285ac27f76b54f5ff4560fc ba2930882b4da3d3ddd5b8697fc127d5
/home/mitsu/develop/petit_tools/sdcard_checker:33:in `block in <main>': Unmatch! (RuntimeError)
from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `open'
from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `<main>'
# sdcard_checker2 /dev/sdb
device = /dev/sdb, check_max = 8,589,934,592
0 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
1,048,576 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
2,097,152 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
3,145,728 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
4,194,304 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
:
:
:
329,252,864 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
66,060,288 16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
132,120,576 32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
198,180,864 48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
264,241,152 64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
330,301,440 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
66,060,288 16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
132,120,576 32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
198,180,864 48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
264,241,152 64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
330,301,440 80640 f005f81d5ee41aa397fc39db563060fe f005f81d5ee41aa397fc39db563060fe
331,350,016 ..
0 0 fa9971f35ad33faaaf100800b4b85b8c fa9971f35ad33faaaf100800b4b85b8c
66,060,288 16128 2ed7a89c5a42bb4040bff4894be82bdb 2ed7a89c5a42bb4040bff4894be82bdb
132,120,576 32256 919cfe23e7079f9077e4360ad127f628 919cfe23e7079f9077e4360ad127f628
198,180,864 48384 c5d3ae3f1ac1b256bb20b044cc491719 c5d3ae3f1ac1b256bb20b044cc491719
264,241,152 64512 dc83f09e6ee934dcc90677af587a629d dc83f09e6ee934dcc90677af587a629d
330,301,440 80640 d207d5474108dac6a8961a17d6f73fa2 f005f81d5ee41aa397fc39db563060fe
/home/mitsu/develop/petit_tools/sdcard_checker:33:in `block in <main>': Unmatch! (RuntimeError)
from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `open'
from /home/mitsu/develop/petit_tools/sdcard_checker:17:in `<main>'
この症状は、代品もまったく同じで、これはもう仕組まれたものと考えて間違いないだろう。要するに「容量偽装」というわけだ。まぁ、ウェアレベリングの仕組みに意図しない不具合があった、という見方もできなくはないけれど。無理に、先頭部分のみパーティションを確保して使う方法もあろうが、さすがに256MBじゃ、いまどき使い物にならんわな。