SSDは高温で保管するとデータが消えていく
SSDには、以下のような現象があり、データを書き込んだ後、そのデータセルについて読み書き全くしないと、データが揮発していく可能性があります。(温度依存で、指数関数的。たぶんデータを記録したセルの酸化被膜から電荷が少しずつ抜けていく?)
解決案
そこで、データが保持されている全領域に、たまにアクセスしてやればどうかという観点でスクリプトを作ってみました(半分AI任せなので、何か間違ってたら指摘ください)。
スクリプトの動作内容
- 上記を使って、コマンドプロンプトを起点に、PowerShellの実行禁止を回避し起動
- 一旦、定番の
DISMとsfcを実行 - 上記にエラーが無ければ、Cドライブの全ファイルを読み込みテスト (これにより、SSDの全書込済み領域にアクセスが走り、SSD自身のファームウェアで不安定とみなされたデータ範囲で別領域に退避されるなどの動作を期待しています。) 処理が長く重いので、実行/I・O優先度を下げて実行します。
スクリプト内容
※ 以下は、文字のカラーハイライトを見やすくするために .ps1 としていますが、実際はmaintenance.bat として保存してください。実行に、管理者権限が必要です。
(もちろん、ps1が実行できる環境の方は、 最初の "コマンドプロンプトからPowerShellを呼ぶおまじない"を削除し、.ps1で保存してもOKです。)
<# :
@echo off & setlocal EnableDelayedExpansion
set BATCH_ARGS=%*
for %%A in (!BATCH_ARGS!) do set "ARG=%%~A" & set "ARG=!ARG:'=''!" & set "PWSH_ARGS=!PWSH_ARGS! "'!ARG!'""
endlocal & Powershell -ExecutionPolicy RemoteSigned -NoProfile -Command "$input|&([ScriptBlock]::Create((gc '%~f0'|Out-String)))" %PWSH_ARGS%
exit/b
: #>
DISM.exe /Online /Cleanup-image /Restorehealth
if ($LASTEXITCODE -ne 0) {
Write-Host "DISM failed with exit code $LASTEXITCODE."
pause
exit $LASTEXITCODE
}
sfc /scannow
if ($LASTEXITCODE -ne 0) {
Write-Host "SFC failed with exit code $LASTEXITCODE."
pause
exit $LASTEXITCODE
}
# The I/O priority set to background mode.
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class BackgroundHelper {
[DllImport("kernel32.dll")]
public static extern bool SetThreadPriority(IntPtr hThread, int nPriority);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentThread();
}
"@
$THREAD_MODE_BACKGROUND_BEGIN = 0x00010000
[BackgroundHelper]::SetThreadPriority([BackgroundHelper]::GetCurrentThread(), $THREAD_MODE_BACKGROUND_BEGIN) | Out-Null
# Set CPU priority to BelowNormal and I/O priority to background mode.
[System.Diagnostics.Process]::GetCurrentProcess().PriorityClass = 'BelowNormal'
# Read all SSD files
Write-Host "Collecting files..."
$origin = 'C:\'
$total = 0
$files = Get-ChildItem -Path $origin -File -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
$total++
if (($total % 1000) -eq 0)
{
Write-Progress `
-Activity "Collecting files" `
-Status "$total files found"
}
$_
}
Write-Progress -Activity "Collecting files" -Completed
$files = @($files)
Write-Host "Found $total files."
Write-Host "Starting read verification..."
$index = 0
foreach ($file in $files)
{
$index++
if (($index % 1000) -eq 0)
{
$percent = [int](($index / $total) * 100)
Write-Progress `
-Activity "Reading files" `
-Status "$index / $total : $($file.Name)" `
-PercentComplete $percent
}
try
{
[void][System.IO.File]::ReadAllBytes($file.FullName)
}
catch
{
Write-Warning "Read failed: $($file.FullName)"
}
}
Write-Progress -Activity "Reading files" -Completed
Write-Host "Done."
pause
余談
自分の経験では、事情により50℃を超える環境で3ヶ月~1年程度保管した外付けSSDは、結構な領域のデータが読めなくなり、読めない領域に差し掛かると、読み込み途中でI/Oアクセスがフリーズするという現象が起きました。(一旦抜いて差すと復活し、読めない領域を読まない限りは普通に動く。)
どれくらい消えるかは、先述のJEDECの資料通りという感じでした。