Предостережение: решение, описанное в данной статье, не является профессиональным, возможно, создано исходя из неправильного понимания строения и принципов работы жестких дисков. Повторение описанных действий может нанести вред оборудованию.


Недавно наткнулся на статью о использовании старых HDD с бэдблоками и подумал, что мой опыт тоже может быть кому-то интересным.


Однажды знакомые попросили помочь разобраться с ноутом, на который они не смогли переустановить Windows. У ноута, судя по виду, была тяжелая жизнь: трещины корпуса, помяты углы, выломаны стойки. Понятно — проблема в повреждении жесткого диска в результате многочисленных ударов, что подтвердил и смарт: более 200 срабатываний G-sensor'а, 500 Reallocated Sector Count и еще есть в Current Pending'е. Ну людям, понятное дело, я поставил SSD, а информацию с их винта скопировал в образ командой:


dd if=/dev/sdb of=/media/hddimages/ht320.img bs=409600 conv=noerror,notrunc,sync

Параметры "conv=noerror,notrunc,sync" нужны, чтоб в случае ошибок чтения определенных секторов, в выходном файле по этим адресам записывались нули, а данные записывались на свое место без смещения.


Бывает, что при чтении большими блоками (400кб) диск не читает весь блок, а меньшими — не считывается лишь 1 сектор. Секторы здесь по 4кб, поэтому после первого прохода dd, если были ошибки чтения, я пробую повторно читать эти участки блоками по 4кб:


n=<отступ>;dd if=/dev/sdb of=/media/hddimages/ht320.img bs=4096 conv=noerror,notrunc,sync skip=$n seek=$n count=100

Параметры skip и seek нужны, чтоб чтение и запись начинались с одинаковым отступом от начала диска. Сам отступ берется из вывода первого выполнения dd, только для соответствия размеру блока, число умножаем на 100.


Иногда диски при обращении к сбойным секторам надолго зависают, да так, что помогает только переподключение к питанию и лет 5 назад был сделан, громко говоря, программно-аппаратный комплекс (с микроконтроллером даже) для автоматизированного чтения сбойных хардов с автоматическим переподключением питания в случае слишком долгого отсутствия ответа. Это было интересно и позволяло, подключив хард и введя команду, дней через 10 получить максимально полный образ. Но подопытный герой статьи не зависал намертво, поэтому необходимости доставать описанный тяжелый костыль не было.


Итак, диск считался, монтирую все разделы образа через losetup с оффсетами начала разделов из fdisk'а, умноженных на размер логического блока в мбр — 512 байт, копирую все данные людям на новый ССД. Если бы диск не монтировался или многие файлы не читались — я бы открыл образ программой R-Studio и восстанавливал бы через нее, но именно с образа.


А вот хард, хоть он и побитый, выкидывать жалко, поэтому я решил как-то его реанимировать. Теоретически контроллер диска отмечает сектора как поврежденные и переназначает на их адреса резервные в случае многократных неудачных попыток записи либо невосстановимых (с помощью ECC) ошибок чтения.


Для начала пробую wipe'нуть диск (dd if=/dev/zero...) и читать после этого: скорость также нестабильна, диск подвисает и иногда выпадает input/output error, но в смарте растет количество релоков и пендингов. Через несколько циклов смарт особо меняться перестал, пендинги не релочатся, а подвисания с ошибками встречаются каждый раз в тех же местах или очень рядом. Пробую принудительно ремапить вручную командой "hdparm --make-bad-sector", но на данной модели это не работает и мне приходит осознание, что просто стирание-чтение, как и запись-чтение не сможет проявить все проблемные места. Ведь если поврежденный бит, вне зависимости от того, что именно в него пытались записать, с большей вероятностью читается как "1", то при записи в него "1", последующее чтение будет проходить без ошибок, но при записи иного паттерна — может набраться достаточно несоответствий, чтоб не справилось ECC и случилась невосстановимая ошибка чтения и через нескольких таких случаев, сектор получил статус "Bad". Кстати, записываемое значение может так накладываться на распределение поврежденных битов, что считанное неправильное значение даже удовлетворит ECC. Поэтому для максимального выявления всех плохих секторов нужно генерировать относительно случайный паттерн, записывать его на диск, считывать и сравнивать значение. Встречаются также нестабильные сектора, которые меняют свои значения постепенно за некоторое время или после обработки его соседей.


С учетом всего перечисленного, я решил реализовать в bash-скрипте следующую стратегию:


  • генерируем случайный паттерн и считаем для него контрольную сумму;
  • читаем смарт;
  • записываем диск нолями;
  • читаем диск;
  • записываем диск случайным паттерном с чтением только что записанного блока и сравнением его чек-суммы;
  • читаем диск после полной записи, проверяя чек-суммы каждого блока;
  • читаем смарт;
  • self-test;
  • goto 1.

Продолжаем так, пока не перестанут случаться неверно считанные сектора и IO-error'ы или пока винт не накроется окончательно. Кстати, как работает self test у данной модели диска, я не представляю; не знаю, чем отличается long от short'а (хотя вероятно лонг работает со всей поверхностью, а шорт — ориентируясь на ранеесобранную статистику, как при форматировании: полное и быстрое). Я надеюсь, что это подтолкнет винт принять во внимание недавний опыт и ремапить сбойные сектора.


Когда я закончил писать bash-скрипт, запустил его и на следующий день проверил результаты — увидел, что очень медленно работает верификация, при этом загрузка процессора не доходит и до 60% ни на одном ядре. Это сподвигло меня поиграться с размером блока, протестировать разные алгоритмы хэша для контрольных сумм, попробовать прямую верификацию diff'ом, а не сравнивание контрольных сумм, но скорости обработки выше 12 мегабайт в секунду достигнуть я так и не смог. В итоге остановился на сравнении diff'ом блоков по 400кб, а контрольные суммы вычисляю только в случае несовпадения лишь для последующего анализа лога.


Скрипт получился такой:
#!/bin/bash
# формат строки запуска hddtest.sh diskdev logfile [blocksize] 

diskdev="$1";
test_log="$2"; #"~/work/hdd/test.log"
blsz="${409600:-$3}";
n="1";
sizebyte=`fdisk -l "$diskdev"|grep "Disk $diskdev:"|cut -d" " -f5`;
let sizebl=$sizebyte/$blsz; #"781428" for 320GB

while true;do
 echo "starting iteration $n";
 dd if=/dev/urandom of=fil bs="$blsz" count=1;
 md5ok=`md5sum fil|cut -d" " -f1`;
 cp fil fil_"$n";
 echo "random pattern md5sum $md5ok">>"$test_log";
 smartctl -A "$diskdev">>"$test_log";
 echo "filling disk with zeroes">>"$test_log";
 dd if=/dev/zero of="$diskdev" bs="$blsz"; #count="$sizebl";
 echo "disk is wiped fully">>"$test_log";
 dd of=/dev/null if="$diskdev" bs="$blsz"; # count="$sizebl";
 echo "writing disk with fil-pattern">>"$test_log";
 i="0";
 while [ "$i" -le "$sizebl" ]; 
 do 
  #echo "writing fil: $i ">>"$test_log";
  dd if=fil of="$diskdev" bs="$blsz" seek="$i";
  dd if=/dev/null of=tst;
  dd if="$diskdev" bs="$blsz" of=tst skip="$i" count=1 conv=notrunc,noerror,sync;
  #md5tst=`md5sum tst|cut -d" " -f1`;
  verf=`diff -s fil tst|sed 's/.* //g'`;
  if [ "$verf" != "identical" ];
  #if [ "$md5ok" != "$md5tst" ]; 
  then 
   md5tst=`md5sum tst|cut -d" " -f1`;
   echo "$i : md5 $md5tst is not ok">>"$test_log"; 
   cp tst tst_"$n"_"$i";
  fi;
  let i="$i"+1;
 done;
 echo "test of full writed with fil-pattern disk">>"$test_log";
 i="0";
 while [ "$i" -le "$sizebl" ]; 
 do
  #echo "after writing test: $i">>"$test_log";
  dd if=/dev/null of=tst;
  dd if="$diskdev" bs="$blsz" of=tst skip="$i" count=1 conv=notrunc,noerror,sync;
  #md5tst=`md5sum tst|cut -d" " -f1`;
  verf=`diff -s fil tst|sed 's/.* //g'`;
  if [ "$verf" != "identical" ];
  #if [ "$md5ok" != "$md5tst" ]; 
  then 
   md5tst=`md5sum tst|cut -d" " -f1`;
   echo "$i : md5 $md5tst is not ok">>"$test_log"; 
   cp tst tst_"$n"_"$i";
  fi;
  let i="$i"+1;
 done;
 smartctl -A "$diskdev" >>"$test_log";
 smartctl -t long "$diskdev">>"$test_log";
 sleep 5000;
 #smartctl -t short "$diskdev">>"$test_log";
 #sleep 240;
 let n="$n"+1;
done

Как после многократного выполнения скрипта показали логи, все сбойные сектора находились в первых 13 ГБ диска, там было несколько "очагов" поражения (вероятно, при ударе головкой побило-поцарапало поверхность). Последние 15 прогонов диск не видел подозрительных (pending) секторов, всё уже было как бы ремаплено, но где-то посредине 13-го Гигабайта периодически неверно считывался один блок или блоки недалеко от него по разным адресам. Причем, один блок мог 2 цикла подряд считаться неверно, затем 2 раза верно и снова раз неверно. Так что отловить последние 10 сбойных секторов — была долгая операция. Всего было ремаплено 1268 секторов! И в конце меня ждал сюрприз: когда всё уже работало стабильно, после очередного self-test'а параметр Reallocated Sector Count стал "0" и о проблемах напоминал только счетчик событий Reallocated Event Count и записи о последних 5 ошибках (с адресом и временем от начала работы), хранимых в журнале.


Несмотря на стабильную работу, я все же решил минимизировать взаимодействие с поврежденной областью, чтоб не травмировать головку о возможные неровности в местах с поврежденной поверхностью пластин, да и местным секторам в долгосрочной перспективе доверять не хотелось. Я просто отступил немного с запасом и создал раздел, начиная с 15-го Гигабайта. И, как показало время, диск чувствует себя довольно хорошо и стабильно работает в носимом ноутбуке уже 10 месяцев.


Хотя полностью доверять восстановленному диску нельзя и экономическая целесообразность затеи сомнительна, но иногда результат — лишь приятное дополнение к хорошему пути.

Комментарии (47)


  1. hssergey
    25.12.2019 19:12

    При таком подходе высок риск повредить головку о запилы, после чего выйдет из строя вся пластина жесткого диска, а если это первая пластина со служебной информацией — диск даже не будет корректно инициализироваться и перестанет определяться в биосе…


    1. Sabubu
      25.12.2019 22:31
      +1

      Ну так это по сути уже убитый диск, это его судьба — сломаться окончательно. Просто перед тем, как это произойдет, можно еще извлечь какую-то пользу, главное бекапы делать не забывать ежедневно.


    1. Tufed
      26.12.2019 10:44

      Если после стольких прогонов, в том числе по проблемным секторам, он вышел в стабильную работу, то можно условно считать что запилов, приводящих к таким результатам, нету. Добавлю от себя: если с диском произошли удары в работе совсем недавно (вчера уронили во время работы и он ёк, вот принесли починить), то я в таком случае диск меняю сразу, а поврежденнй цепляю на пару часов к машине на холостой ход. Головки в таком случае на парковке, а весь мусор, образовавшийся при запиле и летающий внутри диска должен осесть на специальных подушечках фильтрации. Если он не отловится фильтрами то велик риск что он продолжит попадать во время работы меж платинами и головкой вместе с воздушным потоком и вызывать цепную реакцию повреждений диска. Как говорят в таких случаях «посыпался». Обычно в таких случаях ремонтники пытаются побыстрее считать всю информацию, чем и убивают его окончательно. После вскрытия таких пациентов внутри обнаруживается песок, ака бывшее напыление диска, содранное головкой.


      1. hddmasters
        26.12.2019 11:00

        Если после стольких прогонов, в том числе по проблемным секторам, он вышел в стабильную работу, то можно условно считать что запилов, приводящих к таким результатам, нету.

        повреждения полимерного покрытия могут иметь место, но проход головок над ними пока что не приводит к новым контактам слайдера и поверхности. Но это событие носит вероятностный характер.
        а поврежденнй цепляю на пару часов к машине на холостой ход. Головки в таком случае на парковке, а весь мусор, образовавшийся при запиле и летающий внутри диска должен осесть на специальных подушечках фильтрации.

        есть нюанс. если диск уже обнаружил дефекты, то немалая вероятность, что просто так держать головки на парковке он не будет. А будут весьма активно работать процедуры оффлайн скана (не во всех семействах).


        1. Tufed
          26.12.2019 17:50

          Согласен.


        1. faraway644
          26.12.2019 20:02

          И тем не менее, песок на 5400 rpm (минимум) улетит с диска либо в первые же секунды, либо при соприкосновении с головкой. Так что переживать не стоит.


          1. hddmasters
            26.12.2019 20:25
            +1

            Быстренько получим много нового «песочка» на слайдерах в результате контакта с задранными краями полимерного покрытия.


            и получим много новых красивых «рисунков» на поверхности пластин.
            image

            без увеличения это будет так
            image


  1. eumorozov
    25.12.2019 20:07
    +1

    В скрипте невообразимо много лишних кавычек. В bash они в таком количестве однозначно не нужны.


    1. Self_Perfection
      25.12.2019 22:58

      Не согласен, я вижу только одну строку, где кавычки не по делу:

      i="0";

      В остальных случаях они уместны. Ну ещё `FOO` можно заменить на $(FOO) для лучшей читаемости, но в этих местах кавычки всё-таки нужны, в смысле не могут быть просто выброшены.


      1. eumorozov
        26.12.2019 12:04

        Несколько примеров:
        diskdev="$1" — ни в одной системе никогда не видел, чтобы в именах устройств были пробелы или другие специальные символы, которые могли бы привести к ошибке, если нет кавычек.


        n="1", i="0" — кавычки однозначно не нужны.


        echo "starting iteration $n"; — кавычки не нужны, впрочем, и глаз не режет.


        smartctl -A "$diskdev" — кавычки не нужны


        while [ "$i" -le "$sizebl" ]; — кавычки не нужны


        let i="$i"+1; — кавычки не нужны


        Хотя я не знаток стилей форматирования для bash, возможно, это какой-то defensive стиль, но даже в этом случае, кавычки, например, в let i="$i"+1 совершенно необъяснимы.


        1. iDm1
          26.12.2019 13:26

          echo «starting iteration $n»; — кавычки не нужны, впрочем, и глаз не режет.
          Без кавычек, если в $n окажутся специальные символы, то сначала они будут соответствующим образом интерпретированы. К примеру "*" добавит к строке список содержимого текущего каталога. Украшение вывода echo при помощи подобных символов не такая уж и редкость. Использовать echo в shell лучше всегда с кавычками.
          let i="$i"+1; — кавычки не нужны
          В данном случае кавычки не меняют поведения, но для привычки я бы всё равно написал скорее так:
          let "i=$i+1"
          К примеру на случай, когда изначально содержимое "$i" в полной мере не контролируется.
          while [ "$i" -le "$sizebl" ]; — кавычки не нужны
          Без кавычек пустые $i или $sizebl приведут к ошибкам «unknown operand» и «argument expected» соответственно. С кавычками же мы получим пустые строки, в условии воспринимающиеся как ноль.

          В языке shell "[" — это команда, а остальные строки являются её аргументами. Пустой аргумент без кавычек — это отсутствующий аргумент и его место в таком случае займёт следующий, это может в корне поменять логику работы скрипта, не только в случае с test, а с любой командой или функцией.

          Ставя лишние кавычки в shell, хуже не сделаешь, а вот забыв их где нужно — получим проблемы.


          1. eumorozov
            26.12.2019 13:30

            Я описал лишь те случаи, где мы точно знаем, что находится в переменной. Например, i и n в данном скрипте всегда не пусты и всегда содержат целое число по определению.


            Добавлять здесь кавычки, все равно что в обычной программе каждый раз перед делением писать:


            b = 10
            assert b != 0
            a = a / b

            если мы и так знаем, что находится в b, то подобная проверка лишь мозолит глаз. Никто так не делает, кроме junior'ов, недоучивших язык.


            1. iDm1
              26.12.2019 14:34
              +3

              Вы зря сравниваете shell с другими языками, он очень самобытен и сильно отличается не то что от java, а даже от других скриптовых языков. Любая строка в shell без кавычек потенциально может быть внешней командой или файлом и требует обращения к дисковой подсистеме, либо специальным символом, требующим интерпретации. Это фундаментальное отличие и особенность данного языка.

              Отсутствие кавычек вокруг строки в shell-скрипте — это типичная «бомба на будущее», понятие, имеющееся и в других языках программирования. Вы можете скорректировать код и в дальнейшем кавычки потребуются, а изменить все строки вы можете забыть. К тому же это исключит вырабатывание привычки, сделает стиль кода неоднородным и увеличит частоту ваших ошибок.

              Когда вы пишете на shell — практики других языков программирования во многом неприменимы из-за его архитектуры. Если, не смотря на большой опыт в программировании в целом, конкретно с shell вы сталкивались не часто, то вы можете попытаться сделать довольно много ошибочных оптимизаций в коде. Это другой мир, с другой историей становления. В таком случае, возможно, лучше сразу использовать Python и не связываться с shell.


        1. NightSkyST
          26.12.2019 13:46

          echo «starting iteration $n»; — кавычки не нужны, впрочем, и глаз не режет.

          Всм не нужны? Там же 3 слова, по моему опыту в таких случаях echo таки требует кавычки.


          1. eumorozov
            26.12.2019 13:48

            echo выводит все свои аргументы. В кавычках все слова будут переданы одним аргументом, без кавычек каждое слово будет передано в своем аргументе. Если нет подстановок в строке, типа *, как уже указал другой комментатор, то разницы нет совершенно никакой.


            В данном случае, мы знаем, что в $n никогда не будет спецсимволов bash, поэтому кавычки, строго говоря, необязательны.


        1. Self_Perfection
          26.12.2019 13:52

          Да, n="1" пропустил, но в целом — google.github.io/styleguide/shell.xml#Quoting

          Лучше уж насыпать необязательных кавычек, чем думать каждый раз при написании и чтении, точно ли в этой переменной не может быть пробела.


          1. eumorozov
            26.12.2019 13:55

            Ну, автор нарушает этот styleguide многократно в других местах. Например, использует [ вместо [[. Изначально тоже хотел написать об этом, но первый комментарий писал с телефона, и поленился.


          1. Yix Автор
            26.12.2019 20:42
            +1

            За styleguid спс, когда-нибудь осилю и дисциплинируюсь.
            Баш для меня как инструмент, который постоянно под рукой. Обычно пишу почти как попало: набросал, поставив вместо команд эхо, проверил, убрал эхо, раскомментил команды, добавил еще что-то, проверил, если ок — оставляю.
            Если код будет использоваться не только мной либо будет использоваться (и дописываться) через время в дальнейшем, то исправляю синтаксис, отступы, убираю «магические числа» и имена файлов в переменные, могу уложить все по функциям если относительно большой скрипт либо высокая повторяемость кода. Кавычки в случае i=«1» обычно не ставлю — это перед публикацией переусердствовал для единообразия и читабельности (подсветки).
            А вот при выводе переменных в качестве аргументов к командам — стараюсь ставить, ведь значение в переменных в большинстве случаев задаются не вручную, а являются результатом парсинга вывода исполнения команд и лучше перебдеть, чем в какой-то момент получить аналог XSS-атаки.


    1. iDm1
      26.12.2019 12:10

      Наличие и отсутствие кавычек в тех случаях, о которых вы говорите, не влияют на валидность кода и его производительность. Но вполне влияют на его читаемость, а так же, как и любой строгий code style, позволяют снизить процент человеческих ошибок и опечаток при использовании подсветки синтаксиса. По этому я бы не стал избавляться от них намеренно, скорее важно, чтобы стиль был единым в рамках проекта, даже такого небольшого.


      1. eumorozov
        26.12.2019 12:12

        В принципе, согласен, за исключением кавычек для переменных, хранящих целые числа, и кавычек в арифметических операциях. Мне кажется, что в данном случае, они скорее от непонимания для чего нужно экранирование и на что оно влияет, а такое непонимание тоже может привести к нежелательным результатам.


  1. qw1
    25.12.2019 21:40

    но на данной модели это не работает и мне приходит осознание, что просто стирание-чтение, как и запись-чтение не сможет проявить все проблемные места. Ведь если поврежденный бит, вне зависимости от того, что именно в него пытались записать, с большей вероятностью читается как «1», то при записи в него «1», последующее чтение будет проходить без ошибок, но при записи иного паттерна — может набраться достаточно несоответствий
    Нет, так магнитная запись не работает. Используется частотная или фазовая модуляция, а значит, на головку подаются куски синусоид. И если место повреждено (не магнитится), в любом паттерне будет ошибка (если только сбойное место достаточно большое, чтобы не быть исправлено ECC-избыточностью).


  1. papilaz
    25.12.2019 22:37
    +2

    Хороший квест, мне интересно было.


  1. sparhawk
    25.12.2019 22:58
    +1

    Тоже использую диск, выдающий ошибки чтения ближе к краям физических дисков (внутри коробки два диска).

    Решение: разбит на два логических диска C: и D:, совпадающих с физическими, но последние 1 ГБ каждого физического диска не используются разделами (свободны). Уже четыре года никаких ошибок нет.

    По моему опыту пластины ЖД редко умирают целиком и все сразу. Обычно портится только часть. Как правильно, центр или край.


    1. ExtenZ
      26.12.2019 00:17

      Да, я тоже так сдела, но там было в начале хдд 15% плохой остальное хорошее


    1. olegkrutov
      26.12.2019 03:07

      А откуда вы знаете, что трансляция физики в логику у вашего диска именно такая? У большинства современных трансляция идёт полосами характерного размера в десятки мегабайт по каждой из поверхностей, после чего идёт переключение на следующую. То есть если два диска в коробке, то там, во-первых, поверхностей чаще всего используется 4, а во-вторых, трансляция идёт как 0123321001233210.., где каждая цифра — несколько десятков-сотен треков по каждой поверхности. Исключение я видел — ноутбучные Самсунги, но и там нет деления по поверхностям, просто куски большого размера. Вы можете это проверить, запустив какую-нибудь измерялку скорости линейного чтения по всему диску, где он читается. Если все как вы говорите, там будет "пила" скорости с числом зубцов == числу головок, а если как я — монотонно убывающая от начала к концу лесенка. Это оттого, что скорость обмена на внешних и внутренних дорожках отличаются раза в два, к центру скорость падает.


      1. faraway644
        26.12.2019 21:49

        Возможно у sparhawk больше всего были изношены самые нагруженные части диска — области MFT, которые как правило расположены в начале и в середине (резервная MFT) логической части диска.
        Поэтому отбраковка логических частей диска тоже имеет смысл.


        1. hddmasters
          26.12.2019 23:17

          Поэтому отбраковка логических частей диска тоже имеет смысл.

          Попытки заочной отбраковки однозначно не имеют смысла в силу того, что не стоит гадать, где именно находятся проблемы. Необходимо проводить нормальное тестирование диска. И на основании тестов делать вывод о том стоит ли далее этот диск пытаться обслуживать или сразу отправить в утиль.

          области MFT, которые как правило расположены в начале

          MFT может быть фрагментирована и ее куски могут быть разбросаны по всему диску.

          и в середине (резервная MFT) логической части диска.

          MFT mirror — это всего лишь 4 записи (при стандартном размере записи 1024 байта — это 4кб). Также некоторые дисковые менеджеры ставят позицией MFT Mirr второй кластер.

          По всему диску хаотично разбросаны индексные записи, в некоторых из них частота перезаписей была очень высокая и вероятность возникновения проблемы не ниже, чем в местах расположения MFT.

          Пример разброса индексов по диску. обратите внимание на размер ползунка и его позицию.


          Пример: диск обычного пользователя.

          Таблица разделов.


          Построим карту расположения фрагментов MFT


          Результат построения.


          предсказуемым оказался только первый фрагмент, который не самый крупный.


    1. hddmasters
      26.12.2019 10:31

      Тоже использую диск, выдающий ошибки чтения ближе к краям физических дисков (внутри коробки два диска).

      Решение: разбит на два логических диска C: и D:, совпадающих с физическими, но последние 1 ГБ каждого физического диска не используются разделами (свободны). Уже четыре года никаких ошибок нет.

      Вы заблуждаетесь. Вы не можете создать раздел только в границах одной физической пластины. Логическое пространство реализуется из зон чередующихся между всеми головками. Например реализация логического пространства в жестком диске Seagate ST9500325AS. На скриншоте можно увидеть, как идет чередование мини-зон.
      image
      По моему опыту пластины ЖД редко умирают целиком и все сразу. Обычно портится только часть. Как правильно, центр или край.

      Умирает там, где произойдет контакт слайдера и поверхности и появится первичное повреждение полимерного покрытия. Если повреждение полимера серьезно, то как бы вы не пытались создать разделы не затрагивающие места дефектов, то все ваши старания все равно будут насмарку по причине того, что проблему усугубят процедур оффлайн сканирования.


      1. sparhawk
        26.12.2019 11:47

        Спасибо всем за замечания! Значит, не все так просто. После НГ посмотрю, как там этот диск устроен. И заодно модель напишу. Кажется, это Hitachi


        1. hddmasters
          26.12.2019 12:18

          Если Hitachi (HGST), то там чередование небольшими зонами как у Seagate в примере выше. Но порядок чередования зон у накопителя с 2 пластинами и 4 головками будет таким 0,1,2,3,0,1,2,3 а не 0,1,2,3,3,2,1,0 как у Seagate.


  1. Gamliel_Fishkin
    25.12.2019 23:30

    Благодарю за статью.

    Мне кажется, будет лучше, если Вы переименуете статью, заменив слово «Hitachi» на «HDD» или «винчестер». А то заголовок вызывает впечатление, что у фирмы Hitachi большие проблемы.


    1. Yix Автор
      26.12.2019 00:59
      +2

      Спасибо, переименовал. К дискам других производителей подход был бы иной, а для некоторых есть даже правильные инструменты вроде WD_Marvel. На японцах прошивки слишком закрыты и широкодоступных нормальных способов реабилитации нет.


      1. olegkrutov
        26.12.2019 01:58

        Прошивки закрыты на всех более-менее современных накопителях, кроме устаревших (до ряда F3) сигейтов, которым было достаточно uart и усердного курения док из сети. Как минимум ключ для входа в технорежим требуют все, да и служебные команды в широкий доступ не сливаются, а wd marvel и иже с ними есть не от особой открытости, а просто в результате чьих-то раскопок, своих или утащенных чужих. Более-менее правильные инструменты есть для многих современных дисков, но с их ценой тратить время на ремонт диска — это из пушки по воробьям. При этом полноценного ремонта сделать не получится по причине отсутствия для этого необходимых ресурсов, даже если вы можете попасть в служебную область диска. Причина простая — у современного диска, который отправлен в магазин, фирмварь "эксплуатационная". А при самотестировании, которое как раз и скрывает дефекты, калибрует канал чтения-записи и т.д., используется другая, "сертификационная", которая потом перезаписывается. С той, что на диске, отправленном в продажу, ничего интересного уже не сделать...


        1. Gamliel_Fishkin
          26.12.2019 02:43

          Более-менее правильные инструменты есть для многих современных дисков, но с их ценой тратить время на ремонт диска — это из пушки по воробьям.
          Ну так и автор занимается не для заработка или экономии, а просто для забавы (Just for Fun).


          1. olegkrutov
            26.12.2019 02:54

            Я же совсем не в упрек автору, просто, так сказать, вкратце обрисовываю ситуацию :)


  1. Temtaime
    26.12.2019 00:11
    +1

    Автор переизобрёл badblocks -t random?


  1. rantal
    26.12.2019 00:35

    Для вытягивания информации со сбойного диска рекомендую обратить внимание на ddrescue — гораздо удобнее, чем копировать данные с умирающего диска в образ обычным dd. И больше шансов успеть утянуть максимум информации, в случае если ошибки чтения диска прогрессируют.


  1. olegkrutov
    26.12.2019 01:02
    +2

    На самом деле надо было сделать не совсем так. При возможности создаётся карта занятого места при помощи partclone.(fstype), пакет partclone есть даже в репах ubuntu. Ключик -D — это то, что надо. Данные с диска копируются при помощи ddrescue (оно есть в тех же репах, пакет gddrescue). Это утилита, сильно лучше приспособленная для копирования проблемных устройств. В качестве domain файла подсовывается карта, полученная при помощи partclone. Полученные образы данных можно пробовать смонтировать как loop, анализировать, да что угодно делать. Небольшой пример: (битый диск /dev/sdc, на нём нужны данные с первого раздела NTFS)
    partclone.ntfs -D -s /dev/sdc1 -O ./disk_map.domain
    ddrescue -d -f --sparse --domain-logfile ./disk_map.domain /dev/sdc1 ./part.img ./data_rescue.log
    В результате получаем в текущем каталоге файл образа раздела part.img… Если диск доживёт, конечно :)
    А уже если битый диск есть желание потом использовать, то та же ddrescue имеет ключик --log-rates, позволяющий оценить исправные и неисправные участки диска. Если последних мало и они компактно расположены, можно просто создать таблицу разделов с пустым пространством в этом месте. Все тусовки с попытками оживить серьёзно битые участки выйдут себе дороже. Да и манипуляции с контрольными суммами лишние, даже если вы пишете на диск просто нули, по факту на блины льётся шумоподобный сигнал, ничего общего с нашими нулями не имеющий (можно погуглить PRML).


    1. Yix Автор
      26.12.2019 01:23
      +1

      До partclone из консоли, стыдно признаться, за много лет руки не добрались, только через gparted им пользовался. Предполагаю, что с поврежденного диска партклон может не все считать, считая участок незанятым, при том, что полный скан рстудией мог бы найти файлы.
      Понимаю, что данные пишутся не в прямом виде, а применяется хитрое кодирование и модуляции для записи, но по опыту, даже из секторов не способных хранить значение (но читаемых без IO-error'ов), после вайпа читаются 00. возможно там какие-то аттрибуты для пустых юзаются


      1. olegkrutov
        26.12.2019 02:09
        +1

        Насчёт партклона — зависит от файловой системы, которую вы спасаете, но если склероз не изменяет, непрочитанные участки битовой карты (bitmap в случае ntfs) оно трактует как занятые. Точно так делает ntfsprogs, насчёт партклона надо смотреть. Поэтому получается "перебдеть". Полный клон безусловно может дать больше возможностей, но тут нужно прикинуть состояние диска, если у вас считалась битовая карта, а диск сильно поврежден, то проще сделать образ занятого, а уж если это получилось, то спокойно дочитываем остальное. Иначе больше вероятность ушатать головы, читая пустые области. Что же касается нулей, то диску ровно все равно, что хранить, ряд нулей — просто одно из состояний сектора, это не флэш. Если оно прочиталось, то как минимум не с первого раза и на данный момент этот сектор читается, что бы там ни было записано...


  1. dporollo
    26.12.2019 05:33

    Ремап и исключения делались ещё на дятлах, мне даже вспомнить сложно когда это было…


  1. vaniacer
    26.12.2019 11:28
    +1

    Немного переделал скрипт

    переделанный скрипт
    #!/bin/bash
    # формат строки запуска hddtest.sh /dev/disk logfile [blocksize] 
    
     diskdev=$1
    test_log=${2:-~/work/hdd/test.log}
        blsz=${3:-409600}
    sizebyte=$(lsblk $diskdev -dbno SIZE)
      sizebl=$[sizebyte/blsz] #"781428" for 320GB
        iter=( $(seq 0 $[sizebl-1]) )
    
    verificate () {
        verf=$(diff -s fil tst | sed 's/.* //g')
        [[ "$verf" != "identical" ]] && {
            md5tst=( $(md5sum tst) )
            echo "$i : md5 $md5tst is not ok"
            cp tst{,_${n}_$i}
        }
    }
    
    test_disk () {
        case $1 in 'write_disk')
            local write_command="dd if=fil of=$diskdev bs=$blsz seek=$i";;
        esac
        for i in ${iter[@]}; do
            $write_command
            dd if=/dev/null of=tst
            dd if=$diskdev bs=$blsz of=tst skip=$i count=1 conv=notrunc,noerror,sync
            verificate
        done
    }
    
    main_loop () {
        while true; do
            ((n++))
            echo "starting iteration $n"
            dd if=/dev/urandom of=fil bs=$blsz count=1
            md5ok=( $(md5sum fil) )
            cp fil{,_$n}
    
            echo "random pattern md5sum $md5ok"
            smartctl -A $diskdev
    
            echo "filling disk with zeroes"
            dd if=/dev/zero of=$diskdev bs=$blsz #count="$sizebl"
            echo "disk is wiped fully"
            dd of=/dev/null if=$diskdev bs=$blsz # count="$sizebl"
    
            echo "writing disk with fil-pattern"
            test_disk 'write_disk'
    
            echo "test of full writed with fil-pattern disk"
            test_disk
    
            smartctl -A $diskdev
            smartctl -t long $diskdev
            sleep 5000
        done
    }
    
    main_loop &> "$test_log"
    


  1. Firsto
    26.12.2019 16:57

    Сразу вспомнил как в Виктории вырезал сбойные блоки на полуторатеррабайтном Сигейте, то ещё удовольствие… (-?L?-? ?)


    1. hddmasters
      27.12.2019 11:09

      В принципе лучше и продолжать использовать специализированное ПО для тестирования и обслуживания дисков. Можно существенно сэкономить время и не потерять в качестве процедуры. Стоит лишь рассмотреть идеологию тестирования.

      Автору удалось решить задачку подручными средствами. Правда туда были привнесены существенные тормоза в виде проверки прочитанного содержимого. Но в любом его стараниями был достигнут результат.

      1. Все данные пишутся в зашумленном виде, а не в чистом, как представляется автору. При записи пользовательских данных нет разницы будут там нули или случайный паттерн. Это действие даст одинаковый результат в плане дальнейшего качества чтения.
      2. У микропрограмм жестких дисков достаточно серьезные методы контроля целостности прочитанных данных. При некорректируемых за счет ECC ошибках чтения при стандартных АТА командах современный накопитель не отдаст никаких данных, а только сигнализирует об ошибке в регистре ошибок.
      3. Искажение данных может происходить в ОЗУ накопителя при условии ее неисправности.


      записываем диск случайным паттерном с чтением только что записанного блока и сравнением его чек-суммы;
      читаем диск после полной записи, проверяя чек-суммы каждого блока;


      Если есть желание проверить контроллер на предмет исправности его буферного ОЗУ, то в той же Victoria можно выполнить тест записи с DDD. В случае появления читабельных секторов с искаженным содержимым можно будет сделать вывод о необходимости замены PCB с переносом ПЗУ. Этот тест будет работать заметно быстрее варианта предложенного автором. В остальном все сведется к количеству циклов записи-чтения с переназначением (Remap). Если накопитель не совсем труп, то этими стараниями можно будет получить что-то хоть частично годное к эксплуатации. Если же проблема серьезна, то все эти действия приведут к запиливанию пластин.




      1. Yix Автор
        27.12.2019 12:17

        А можно уточнить. Допустим читаются неверные данные из-за неисправности ОЗУ, но почему именно по определенным секторам?
        Или вот другая похожая для меня ситуация: диск (wd320 3.5) записывается и читается блоками по 4кб нормально и даже график Виктория гладкий рисует, но при чтении блоков размером 400кб с определенными секторами внутри блока — стабильно вылетают ошибки буфера.
        То есть вопрос почему из-за озу могут гарантировано случаются чтения при работе с конкретными секторами. Я то себе из предположений выстроил себе какую-то модель в голове, но хотелось бы знать версию специалиста.


        1. Yix Автор
          27.12.2019 12:56

          поправка к последнему абзацу: «могут гарантировано случаться ошибки чтения»


          1. hddmasters
            27.12.2019 16:31

            Версий несколько. Необходимы проверки.
            1. Ошибки в драйвере ОС. Некорректно разбирается регистр ошибок и в некоторых случаях забирается содержимое пустого буфера. Отсюда гладкий скан, но прочитанное в некоторых точках не соответствует записанному.
            2. Ошибки в микропрограмме жесткого диска.

            Для исследования ошибок желательно сделать множественные попытки записи и чтения с сохранением результата чтения в файлы. После исследовать разночтения между тем что прочиталось в разных версиях и тем, что должно было быть записано.

            То есть вопрос почему из-за озу могут гарантировано случаются ошибки чтения при работе с конкретными секторами.

            Это ошибки чтения не из-за ОЗУ. Ошибки в ОЗУ зачастую никак не регистрируются, если не проводить дополнительный контроль целостности данных, как например это делали вы, и носят случайный характер. А вот ошибки в виде некорректного ремапа, когда точечно накопитель может быстро выдавать ABR при попытке чтения или устанавливать иные биты в регистре флагов и эти ошибки не регистрируются драйвером работающим с устройством могут приводить к ситуации описанной вами.