Как стать автором
Обновить
2436.24
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Клонируем GPT-диск с 512B-сектором на диск с 4K-сектором в Linux. Подводные камни с EFI, NTFS и LVM

Время на прочтение9 мин
Количество просмотров13K

Для современного компьютера диск с 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 и на какую-то из них ему нужно писать данные.

Классические способы (dd, cat, pv) прекрасно подходят для клонирования LVM-разделов, если диски имеют одинаковый размер сектора. Но в моём случае после клонирования ими LVM-раздел не запустился. Оказалось, что в него всё-таки жёстко вшит размер сектора. Ниже я расскажу, как это обошёл. vgchange делать не пришлось.

▍ 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


▍ 1.5. А что насчёт TRIM?


Можно попробовать увеличить скорость клонирования, если перед клонированием сделать TRIM целого диска-приёмника.

blkdiscard /dev/sdb

Или одного раздела.

blkdiscard /dev/sdb3

После клонирования (простыми программами типа dd, pv, cat) можно тримнуть склонированную файловую систему. Но делать это нужно лишь после того, как диск-источник удалён, а склонированная ФС подмонтирована.

Если вы дата-параноик, то не делайте этого, так как потом не сможете с диска восстановить удалённые файлы.

fstrim /mnt/mount_point

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

Рейд-массивы тоже, как правило, TRIM не поддерживают, так как содержание ячеек после TRIM по стандартам не определено, а рейд-массиву нужно считать контрольные суммы.

Манипуляции с TRIM перед/после клонирования вряд ли дадут какой-то существенный выигрыш, но хуже точно не будет.

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-разделом на диске-приёмнике, а потом клонировать каждый раздел в отдельности.

Соответственно, на диске-приёмнике я создал 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 спроектирована неидеально. Она выходит за пределы своего уровня абстракции, совершает layering violation, о которых говорил Эдуард Шишкин (разработчик ReiserFS 4) в своём интервью. А именно непонятно, зачем в первый сектор NTFS записан размер сектора физического диска, размер NTFS в секторах, число скрытых секторов.

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

ntfsinfo -m /dev/nvme0n1p4

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

Что интересно, размер сектора диска совершенно безразличен Linux-драйверу ntfs-3g. Разделы NTFS под Linux прекрасно видны даже после клонирования 512B -> 4KiB.

Решать проблему «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



Вооружившись описанием формата NTFS boot-сектора, я написал свою утилитку для его модификации после клонирования.

Естественно, я полностью отказываюсь от любой ответственности, если вы будете её использовать. Однако мне она помогла. Вот репозиторий на 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


Но есть одна тонкость. Backup NTFS boot сектор хранится в последнем секторе раздела. А точнее в первых 512 байтах последнего сектора. Что даёт его разное положение в зависимости от размера сектора. Поскольку я не был уверен, что в последних 8 секторах нет никакой важной информации, то перед использованием своей проги я немного уменьшил размер NTFS-фс, применил свой скрипт, а потом опять её увеличил. Вот так это выглядело:

ntfsresize --size 260G /dev/nvme0n1p5
./ntfs_512_to_4k fix /dev/nvme0n1p5
ntfsresize /dev/nvme0n1p5

▍ 3.3. Windows 10 и Windows 7


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

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

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

▍ 3.4. Скрытые разделы Windows



Если посмотреть вывод gdisk, то мы увидим кроме основного раздела Windows ещё 2 скрытых раздела с кодами 2700 и 0C01, размерами примерно 500MiB и 16MiB.

Код 2700 соответствует разделу со средой восстановления. Этот раздел отформатирован в NTFS. Поэтому с ним поступаем как и было объяснено выше.

Посмотрим размер сектора, который зашит с помощью ntfsinfo и скорректируем, если нужно.

А вот с разделом с кодом 0C01 (обозначение «Microsoft reserved» в gdisk) оказалась какая-то странность. На всех компьютерах, где я его смотрел, он не имел никакой файловой системы и был заполнен нулями. Поэтому я просто склонировал его dd.

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. Его лучше смотреть в полном размере в отдельном окне.

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 28: ↑27 и ↓1+37
Комментарии38

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds