Расширение разделов без потери данных

    Суть


    Разработал программу для простого расширения раздела и файловой системы (xfs, ext3,4) без потери данных. github.com/rekby/fsextender/releases/latest

    Исходная проблема


    После расширения диска виртуальной машины c ос семейства linux расширить внутри неё раздел данных.

    Файловая система занимает весь диск, без таблицы разделов


    В самом простом случае (одна файловая система на весь диск, без разделов) достаточно вызвать xfs_growfs или resize2fs и дело сделано.

    Файловая система на LVM-томе


    Если файловая система работает поверх LVM — расширение немного усложняется, но всё еще безопасно: добавить новый раздел, создать там физический том LVM, добавить его в LVM группу, расширить логический том и после этого расширять файловую систему. Побочным эффектом тут будет нагромождение разделов и физических томов, если место добавляется постепенно несколько раз. порциями. А если используется msdos-таблица разделов, то надо еще вспомнить про использование расширенных разделов, иначе их количество ограничено 4-мя штуками и потом надо шаманить и переписыванием таблицы разделов.

    Файловая система в обычном разделе


    Самый опасный вариант для ручного исполнения: нужно вручную удалить и пересоздавать раздел так, чтобы он начинался там же где и предыдущий, а заканчивался на последнем свободном секторе диска.
    Тут требуется повышенная внимательность и аккуратность — при ошибке в цифрах можно легко потерять все данные. Кроме этого в качестве побочного эффекта меняются GUID GPT-разделов, к которым могут быть какие-то привязки в настройках системы.

    Способ решения


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

    Языком реализации выбран go, т.к. на выходе очень просто получить статический бинарник, без внешних зависимостей, это важно т.к. один и тот же бинарник должен запускаться разных версиях ОС от centos 5.4 x86 до последних ubuntu 14.04 x64 и далее — по мере обновления шаблонов.

    Итог


    Написаны две библиотеки для работы напрямую с таблицами разделов: github.com/rekby/mbr — для работы с таблицей разделов msdos (внешний интерфейс не очень, но работает исправно) и github.com/rekby/gpt — для работы с таблицами GPT.

    Написан расширитель разделов и файловых систем. Он умеет:
    1. Расширять основные (primary, не logical) разделы таблицы msdos и разделы GPT по месту, без потери данных, флагов, индентификаторов и т.п. (если ядро поддерживает, то и без перезагрузки — как например в ubuntu 14.04).
    2. Расширять физические тома LVM (LVM-PV) по месту без потери данных, если возможно расширить раздел под LVM-PV.
    2. Создавать новые разделы для расширения LVM (во избежании недоразумений разделы создаются только на дисках, где уже есть готовая таблица разделов).
    3. Фильтровать диски для создания новых разделов (по умолчанию новые разделы создаются только на тех дисках, где уже размещена эта LVM-группа, фильтры можно отключить).
    4. Расширять файловые системы ext3,ext4, xfs.
    5. Автоматом определяет нужна ли перезагрузка после перезаписи таблицы разделов.

    Работа с таблицами разделов происходит напрямую перезаписью данных в служебных областях диска. Так получается безопаснее, чем работа через инструменты вроде parted, т.к. время нарушения целостности таблицы разделов меньше, а в ряде случаев отсутствует совсем.
    Работа с LVM и расширение файловых систем делается через внешние вызовы соответствущих команд (pvcreate, xfs_growfs и т.п.), так что эти команды должны быть установлены и присутствовать в PATH, т.е. быть доступными для вызова просто по имени. В подавлящем большинстве случаев это условие выполняется естественным образом.

    В итоге сейчас расширение файловой системы и нижележащий разделов выглядит так:
    fsextender /home --do
    


    или так:
    fsextender /dev/sda2 --do
    


    или так:
    fsextender /dev/lvm-group/lvm-volume --do
    
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 12
    • +1
      Спасибо, очень интересно. ptmax не умеет GPT, а прогресс идёт…
      • 0
        программа ptmax была как раз вдохновителем
        • +3
          Я открыт к вашим пул реквестам.
          • +5
            спасибо за ptmax, на вашем исходнике я наглядно посмотрел, что работа с таблицей разделов это не так сложно как кажется. Ну и основную идею у вас взял — просто менять в таблице размеры раздела.

            К сожалению C могу читать, но опыта написания нет (только С++ и только под винду и то лет 8 назад) и pull-реквест в разумное время с разумным качеством сделать бы не получилось.
        • 0
          В случае LVM в обычном разделе (CentOS 6-7 по-умолчанию) будет пересоздаваться раздел с новым конечным адресом или его расширение делается только через экстент?
          • 0
            Про экстент я не очень понял что имелось ввиду, но если есть альтернатива — расширить существующий раздел или создать новый сразу за существующим то выбор будет в пользу расширения существующего раздела, без создания новых.
            • 0
              Спасибо за ответ и полезную утилиту!
          • 0
            На обновлённом RHEL 6.8 запуск fsextender пару раз убил ФС и в выводе появилась куча ошибок:
            fsextender
            [root@TestVM ~]# ./fsextender /dev/mapper/VolGroup-lv_root --do
            2017/01/24 17:02:02 Can't get disk size: /dev/loop0
            2017/01/24 17:02:02 Can't get disk size: /dev/loop1
            2017/01/24 17:02:02 Can't get disk size: /dev/loop2
            2017/01/24 17:02:02 Can't get disk size: /dev/loop3
            2017/01/24 17:02:02 Can't get disk size: /dev/loop4
            2017/01/24 17:02:02 Can't get disk size: /dev/loop5
            2017/01/24 17:02:02 Can't get disk size: /dev/loop6
            2017/01/24 17:02:02 Can't get disk size: /dev/loop7
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop0,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop3,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop6,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop7,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop1,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop2,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop4,
            2017/01/24 17:02:02 I can't work with non msdos/gpt table partition. TODO.: /dev/loop5,
            2017/01/24 17:02:02 DO  0: [Type: type_PARTITION, Path: /dev/sda2, Size: 19.5GiB (+10.0GiB), Child: 1, PartNum=2]
            2017/01/24 17:02:02 Partition resized: /dev/sda2 to 29.5GiB (+10.0GiB)
            2017/01/24 17:02:02 NEED REBOOT!
            2017/01/24 17:02:02 DO  1: [Type: type_LVM_PV, Path: /dev/sda2, Size: 19.5GiB (+10.0GiB), Child: 4, ExtentSize: 4.0MiB]
            2017/01/24 17:02:02 LVM PV Resized: /dev/sda2 to 19.5GiB (+0.0B)
            2017/01/24 17:02:02 DO  2: [Type: type_SKIP, Path: /dev/sda3, Size: 0.0B (+10.0GiB), Child: 3, Reason: Partition layout optimization. Partition number may be wrong becouse it optimize too.]
            2017/01/24 17:02:02 Skip item: Partition layout optimization. Partition number may be wrong becouse it optimize too. type_PARTITION_NEW /dev/sda3 0.0B
            2017/01/24 17:02:02 DO  3: [Type: type_SKIP, Path: /dev/sda3, Size: 0.0B (+0.0B), Child: 4, Reason: Partition layout optimization. Partition number may be wrong becouse it optimize too.]
            2017/01/24 17:02:02 Skip item: Partition layout optimization. Partition number may be wrong becouse it optimize too. type_LVM_PV_NEW /dev/sda3 0.0B
            2017/01/24 17:02:02 DO  4: [Type: type_LVM_GROUP, Path: VolGroup, Size: 19.5GiB (+0.0B), Child: 5, ExtentSize: 4.0MiB]
            2017/01/24 17:02:02 Free space on LVM_GROUP 'VolGroup' 0.0B
            2017/01/24 17:02:02 DO  5: [Type: type_LVM_LV, Path: VolGroup/lv_root, Size: 17.5GiB (+0.0B), Child: 6]
            2017/01/24 17:02:02 Resize LVM_LV VolGroup/lv_root to 17.5GiB(+0.0B)
            2017/01/24 17:02:02 DO  6: [Type: type_FS, Path: /dev/dm-0, Size: 17.5GiB (+0.0B), Child: -1, FS: ext4]
            2017/01/24 17:02:02 Filesystem doesn't extend. Log of resize:
            stdout:
            stderr: resize2fs 1.41.12 (17-May-2010)
            The filesystem is already 4589568 blocks long.  Nothing to do!
            
            
            2017/01/24 17:02:02 Sleep a second before retry.
            2017/01/24 17:02:03 Filesystem doesn't extend. Log of resize:
            stdout:
            stderr: resize2fs 1.41.12 (17-May-2010)
            The filesystem is already 4589568 blocks long.  Nothing to do!
            
            
            2017/01/24 17:02:03 Sleep a second before retry.
            2017/01/24 17:02:04 Filesystem doesn't extend. Log of resize:
            stdout:
            stderr: resize2fs 1.41.12 (17-May-2010)
            The filesystem is already 4589568 blocks long.  Nothing to do!
            
            
            2017/01/24 17:02:04 Sleep a second before retry.
            2017/01/24 17:02:05 Filesystem doesn't extend. Log of resize:
            stdout:
            stderr: resize2fs 1.41.12 (17-May-2010)
            The filesystem is already 4589568 blocks long.  Nothing to do!
            
            
            2017/01/24 17:02:05 Sleep a second before retry.
            2017/01/24 17:02:06 Filesystem doesn't extend. Log of resize:
            stdout:
            stderr: resize2fs 1.41.12 (17-May-2010)
            The filesystem is already 4589568 blocks long.  Nothing to do!
            
            
            NEED REBOOT AND START ME ONCE AGAIN.
            [root@TestVM ~]# reboot
            
            Broadcast message from root@TestVM
                    (/dev/pts/0) at 17:02 ...
            
            The system is going down for reboot NOW!
            [root@TestVM ~]#
            login as: root
            root@192.168.0.27's password:
            Last login: Tue Jan 24 17:01:02 2017 from computer.domain.tld
            [root@TestVM ~]# ./fsextender /dev/mapper/VolGroup-lv_root --do
            2017/01/24 17:02:56 Can't get disk size: /dev/loop0
            2017/01/24 17:02:56 Can't get disk size: /dev/loop1
            2017/01/24 17:02:56 Can't get disk size: /dev/loop2
            2017/01/24 17:02:56 Can't get disk size: /dev/loop3
            2017/01/24 17:02:56 Can't get disk size: /dev/loop4
            2017/01/24 17:02:56 Can't get disk size: /dev/loop5
            2017/01/24 17:02:56 Can't get disk size: /dev/loop6
            2017/01/24 17:02:56 Can't get disk size: /dev/loop7
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop5,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop7,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop2,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop3,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop4,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop6,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop0,
            2017/01/24 17:02:56 I can't work with non msdos/gpt table partition. TODO.: /dev/loop1,
            2017/01/24 17:02:56 DO  0: [Type: type_PARTITION, Path: /dev/sda2, Size: 29.5GiB (+0.0B), Child: 1, PartNum=2]
            2017/01/24 17:02:56 Partition resized: /dev/sda2 to 29.5GiB (+0.0B)
            2017/01/24 17:02:56 DO  1: [Type: type_LVM_PV, Path: /dev/sda2, Size: 19.5GiB (+10.0GiB), Child: 2, ExtentSize: 4.0MiB]
            2017/01/24 17:02:56 LVM PV Resized: /dev/sda2 to 29.5GiB (+10.0GiB)
            2017/01/24 17:02:56 DO  2: [Type: type_LVM_GROUP, Path: VolGroup, Size: 19.5GiB (+10.0GiB), Child: 3, ExtentSize: 4.0MiB]
            2017/01/24 17:02:56 Free space on LVM_GROUP 'VolGroup' 10.0GiB
            2017/01/24 17:02:56 DO  3: [Type: type_LVM_LV, Path: VolGroup/lv_root, Size: 17.5GiB (+10.0GiB), Child: 4]
            2017/01/24 17:02:56 Resize LVM_LV VolGroup/lv_root to 27.5GiB(+10.0GiB)
            2017/01/24 17:02:56 DO  4: [Type: type_FS, Path: /dev/dm-0, Size: 17.5GiB (+10.0GiB), Child: -1, FS: ext4]
            2017/01/24 17:03:01 Resize filesystem: /dev/dm-0 to 27.5GiB (+10.0GiB)
            OK
            [root@TestVM ~]# df -h
            Filesystem            Size  Used Avail Use% Mounted on
            /dev/mapper/VolGroup-lv_root
                                   27G  1.3G   25G   5% /
            tmpfs                 939M     0  939M   0% /dev/shm
            /dev/sda1             477M  110M  343M  25% /boot
            

            • 0
              Может быть виноват обновлённый fdisk? Он при запуске ругается на «DOS-compatible mode is deprecated» и при создании нового раздела неверно выставляет его начало после удаления предыдущего.
              • 0
                По выводу предположительно всё правильно.

                А это можно как-то воспроизвести?

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

                От fdisk тут зависимости нет — с таблицей разделов я работаю напрямую на диске.

                Ошибки про loop-девайсы это номально, они ни на что не влияют. Ошибки в первом выводе это про то что ядро не смогло распознать увеличение нижележащего раздела без ребута и не получается PV сразу расширить, т.е. тоже ничего страшного.
                • 0
                  Прошу прощения, пропустил уведомлялку.

                  Сейчас перестало воспроизводиться, хотя тогда запорол 3 виртуалки подряд простым запуском после yum update. Может быть попалась неудачная версия ядра или ещё что-то, после этого я обновлял шаблоны.
                  • 0
                    что-то забыл сразу ответить.

                    Ну если всё до сих пор хорошо — то хорошо.
                    Если что — о проблемах можно писать. Эффективнее будет в issues на github — я их лучше получаю, чем уведомления отсюда.

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