Клонируем GPT-диск с 512-байтным сектором на диск с 4K-сектором в Linux

nuz_r7zklesrdsalsiy6maismlo.png

Для современного компьютера диск с 4К сектором выглядит предпочтительнее, чем с олдскульным 512B.

Практически у всех современных файловых систем размер кластера по умолчанию имеет размер 4KiB или больше. Поэтому использование 512B сектора несколько снижает производительность, а также увеличивает коэффициент умножения записи (Write Amplication) у SSD, что уменьшает ресурс.

Более того, почти невозможно найти современные диски с размером более 4ТБ с сектором 512N. Если и диск репортует такой сектор в 512 байт, то, как правило, это 512E — эмулируемый, который используется в основном для совместимости со старыми контроллерами. А в реальности на физическом уровне используется 4К или даже больше (больше в основном у SSD).

Поэтому при покупке нового диска я выбрал диск с сектором 4КiB. И передо мной встала задача клонирования старого диска с 512B сектором (GPT) на новый c сектором 4KiB. Я хотел сохранить установленные Linux, Windows 10, Windows 7 и тома LVM, чтобы не заниматься переустановками ОС. В процессе чего всплыло несколько подводных камней.
Начну с того, что всем советую загрузочные диски (как и прочие, которые >= 2ТБ) делать в разметке GPT. Ибо это очень удобно.

Для GPT-дисков уже не нужна магия хитрых загрузчиков, которые записываются в MBR и многоступенчатым образом загружают вначале себя, а потом и операционную систему.

Достаточно записать загрузчик в специальный EFI-раздел, указать в биосе, что мы хотим загружать именно этот загрузчик и всё. Если биос неудобный или с усеченным функционалом, то я использую программу Hasleo EasyUEFI.

Итак, вернёмся к моей задаче. У меня на диске стоят в мультизагрузке:

  1. Calculate Linux (btrfs)
  2. Windows 10 LTSC (ntfs)
  3. Windows 7 (ntfs)

Загрузчики установлены в специальном EFI-разделе с кодом EF00 (так он видится и вводится в Linux-утилите gdisk для разметки диска).

1. Клонирование


▍1.1. Отмонтируем смонтированные файловые системы


Список смонтированных файловых систем проще всего посмотреть командой df.
Отмонтируем (по имени раздела или конечной папки):
umount /dev/nvme0n1p1
umount /dev/nvme0n1p2
umount /mnt/storage
...

▍1.2. Отключаем активные Volume Groups в LVM

vgchange -a n vg_name

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

▍1.3. Клонирование стандартными утилитами


Вначале я просто склонировал один диск на другой.

Классический способ это:

dd if=/dev/nvme0n1 of=/dev/nvme1n1 bs=16M status=progress

Хотя, лично я предпочитаю вот такой:
pv < /dev/nvme0n1 > /dev/nvme1n1

Программа pv показывает полосу копирования, текущую скорость, ожидаемое время и использует/подбирает размер блока для более быстрого копирования.

Если на системе нет ни pv, ни dd то можно использовать cat:

cat < /dev/nvme0n1 > /dev/nvme1n1

В этом случае тоже будет всё скопировано быстро, то без всяких плюшек типа полосы копирования. Некоторые админы шаманского типа считают, что cat — самая оптимизированная прога для копирования потоков данных и поэтому делают так:
cat < /dev/nvme0n1 | pv > /dev/nvme1n1

или так:
cat < /dev/sda | pv | cat > /dev/sdb

Сочетают оптимизированность cat и плюшки pv. По моим прикидкам достаточно pv. Я не смог увидеть какого-то существенного выигрыша.

Также клонировать можно разделы в отдельности.

pv < /dev/sda1 > /dev/sdb1

Вышеперечисленные способы клонирование, естественно, работают когда источник (source) по размеру меньше или равен назначению (target).

Вообще во многих случаях клонировать удобно используя флэшку с Clonezilla. Но, как выяснилось, она не может корректно отработать случай с клонированием с 512B диска на 4КiB-диск. Хотя в остальном Clonezilla хороша. Она умеет клонировать только занятые сектора, что существенно экономит время.

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


Из-за того, что 4К-сектор больше в 8 раз, чем 512B потребуется после клонирования ещё изменить таблицу разделов. Так как разделы задаются в секторах. Это можно сделать вручную по раздельно с помощью gdisk, а можно использовать sfdisk.

В таблице которую показывает gdisk (внутренняя команда p) можно увидеть что-то подобное:

Command (? for help): p
Disk /dev/disk1: 15634432 sectors, 7.5 GiB
Sector size (logical/physical): 512/512 bytes

Disk identifier (GUID): 70D5FAFF-4AC9-42C6-A552-0603CE032B8D
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 15634398
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         8390655   4.0 GiB     0700  Shared (FAT) data
   2         8390656        12584959   2.0 GiB     8300  Linux ext3fs data
   3        12584960        15634398   1.5 GiB     2700  Linu

Мы видим размер логического и физического секторов, а также в таблице есть начальные и конечные сектора. Стартовый сектор нам достаточно разделить на 8, чтобы получить номер сектора для 4К-диска, а вот конечный сектор считает по чуть более сложной формуле. Мы прибавляем 1, делим на 8, и вычитаем 1. В консоли выполнить вычисления можно так:
echo -n 'Begin '; echo "2048 / 8" | bc
echo -n 'End '; echo "(8390655 + 1) / 8 - 1" | bc

Или примерно так:
perl -l -e "print 'End ', (8390655 + 1) / 8 - 1"

Можно отредактировать все разделы оптом. Мы записываем таблицу разделов в файл, а потом редактируем его.
sfdisk -d /dev/nvme0n1 > gpt.txt

И заливаем заново на диск:
cat gpt.txt > sfdisk /dev/nvme0n1

После любого изменения таблицы дисков желательно дать ядру знать об этом командой:
partprobe /dev/nvme0n1

2. Клонирование EFI-раздела.


Вот тут и подстерёг меня первый подводный камень. На дисках с сектором 512 байт размер EFI раздела составляет около 100М. Но мы не можем просто склонировать этот раздел на конечный диск. Потому как для EFI-раздела есть требование, что число секторов в нём должно быть не менее 65527.
Для расширенного формата дисков объемом в машинном формате (4 КБ на сектор) минимальный размер составляет 260 Мб из-за ограничения формата файла FAT32. Минимальный размер раздела для дисков FAT32 вычисляется как размер сектора (4 КБ) x 65527 = 256 МБ.

Это ограничение не затрагивает диски расширенного формата 512e, так как их размер эмулированного сектора составляет 512 байт. 512 байт x 65527 = 32 МБ, что меньше, чем минимальный размер в 100 МБ для этой секции. Документация Microsoft.

У меня раздел на старом диске был как раз около 100МБ. Поэтому мне пришлось вначале создать структуру разделов на диске-приёмнике, а потом клонировать по раздельно.

Соответственно на диске приёмнике я создал EFI-раздел размером 270МБ. Отформатировал его, а потом скопировал все файлы со старого раздела на новый.

Создание FAT32 на разделе 4К-диска:

mkfs.vfat -v -F 32 -s 1 -S 4096 /dev/nvme0n1p2

Монтируем старый и новый EFI-разделы:
mount -t vfat /dev/nvme1n1p4 /mnt/oldefi
mount -t vfat /dev/nvme0n1p4 /mnt/newefi

Копирование файлов загрузчиков со старого EFI-раздела на новый:
cp -a /mnt/oldefi/. /mnt/newefi

3. Клонируем разделы с NTFS


Поскольку по умолчанию размер кластера у NTFS равен 4К, то я думал никаких проблем не возникнет. Как же я ошибался!

NTFS спроектирована неидеально. Она выходит за пределы своего уровня абстракции, совершает access violation, о которых говорил Эдуард Шишкин (разработчик ReiserFS 4) в своём интервью. А именно непонятно, зачем в первый сектор NTFS записан размер сектора физического диска, размер NTFS в секторах, число скрытых секторов.

Посмотреть информацию о NTFS под Linux:

ntfsinfo -m /dev/nvme0n1p4

Из-за того, что в NTFS жёстро зашит размер сектора разделы отображаются как RAW. Решать эту проблему можно несколькими способами.

На текущий момент ни одна утилита для клонирования не умеет корректно клонировать NTFS-разделы между дисками с разным размером сектора, в том числе Clonezilla. Единственная программа, которая анонсирует эту функцию — это HdClone. Но она это делает топорно и не совсем верно, что лучше использовать мою самописную утилиту.

Ужасный случай связанный с HdClone.
Вдохновившись анонсированной функций клонирования с 512 на 4К я решил попробовать эту прогу. Но в бесплатной версии не было функции клонирования отдельных разделов. Мне было жалко платить 20 евро и решил найти хакнутую программу. Нашёл. Проверил 10 антивирусами. Всё ОК. Запустил. И на всех моих дисках была испорчена $MFT. Я пока ещё не разобрался были ли они зашифрованы или просто испорчены, так как никакого требования не было оставлено.

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

Потом я уже ради чистоты эксперимента я использовал официальную версию. И что? Она склонировала NTFS-раздел некорректно. Не заполнила NTFS backup boot-сектор. И, насколько я помню, chkdsk увидел ошибки на NTFS-разделе после клонирования.

▍3.1. Пересоздаём загрузочный сектор NTFS c помощью программы TestDisk


Прекрасная программа, которая есть как под Windows, так и в большинстве репозиториев Linux. В данном случае опция «Rebuild BS» выручает, но и она не всегда корректно работает. Проблема в том, что эта функция работает исходя из битовой карты и $MFT. Для целей восстановления данных — это хороший подход, но для клонирования лучше просто пересчитать NTFS boot sector.

▍3.2. Моя утилита ntfs_512_to_4k

Естественно, я полностью отказываюсь от любой ответственности, если вы будете её использовать. Однако мне она помогла. Вот репозиторий на GitHub.

Примеры использования:

Показать информацию из загрузочного сектора NTFS и его копии.

./ntfs_512_to_4k show /dev/nvme0n1p5

Переделать информацию в загрузочных секторах NTFS из 512 в 4К-секторы (после клонирования)
./ntfs_512_to_4k fix /dev/nvme0n1p5

Откатить изменения в загрузочных секторах с 4К на 512B-сектора
./ntfs_512_to_4k unfix /dev/nvme0n1p5

▍3.3. Windows 10 и Windows 7


Windows 10 после коррекции NTFS заработала отлично.

А вот Windows 7 мне не удалось заставить работать. Совсем. Видимо при установке куда-то в неё записывается размер сектора диска и она выдаёт самые разнообразные ошибки, но не хочет работать, если он изменился.

Для корректного перенесения Windows 7 я попробовал использовать xcopy и robocopy с ключами для копирования всех прав. Но это не помогло. Windows 7 так и не смогла запуститься.

4. Перенос Volume Groups в LVM


Оказывается, где-то в формате LVM жёстко прописывается размер сектора. Поэтому вместо клонирования пришлось добавить новые разделы в Volume Group. Перенести информацию с помощью pvmove. Удалить старые разделы из Volume Group.

Но перед этих в настройках /etc/lvm/lvm.conf нужно раскомментировать возможность нахождения в одной VG дисков с разным размером сектора.

allow_mixed_block_sizes = 1

Объявляем раздел на новом физическом диске частью LVM-инфраструктуры:
pvcreate /dev/nvme0n1p9

Расширяем им Volume Group:
vgextend vg_name /dev/nvme0n1p9

Переносим данные со старого диска на новый:
pvmove /dev/nvme1n1p9 /dev/nvme0n1p9

Удаляем старый диск из Volume Group:
vgreduce vg_name /dev/nvme1n1p9

5. Клонирование раздела c BTRFS


Прошло отлично. Никаких коррекций загрузочных секторов не потребовалось.

6. Заключение


Как мы видим сложности возникают при клонировании EFI-раздела, NTFS-файловых систем, а также Volume Groups от LVM. Но они решаемые.Благодарности
За изображение спасибо TripletConcept. Его лучше смотреть в полном размере в отдельном окне.

oug5kh6sjydt9llengsiebnp40w.png

© Habrahabr.ru