Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Для современного компьютера диск с 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.
Итак, вернёмся к моей задаче. У меня на диске стоят в мультизагрузке:
- Calculate Linux (btrfs)
- Windows 10 LTSC (ntfs)
- 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 МБ.У меня раздел на старом диске был как раз около 100МБ. Поэтому мне пришлось вначале создать структуру разделов на диске-приёмнике, а потом клонировать по раздельно.
Это ограничение не затрагивает диски расширенного формата 512e, так как их размер эмулированного сектора составляет 512 байт. 512 байт x 65527 = 32 МБ, что меньше, чем минимальный размер в 100 МБ для этой секции. Документация Microsoft.
Соответственно на диске приёмнике я создал 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-разделе после клонирования.
Если вы хорошо владеете отладчиком и сможете разобраться с тем, что именно произошло, жду вас в личке для взаимовыгодного сотрудничества.
Потом я уже ради чистоты эксперимента я использовал официальную версию. И что? Она склонировала 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. Его лучше смотреть в полном размере в отдельном окне.