понедельник, 22 марта 2010 г.

gpart: изменение размера раздела

Доделал поддержку изменения размера разделов для GEOM класса PART. На данный момент идеи "что бы туда ещё добавить" закончились, поэтому решил выложить патчи.

Немного о цели патчей. Были у меня несколько машин, на которые я уже давно для тестов ставил FreeBSD с ZFS. Они полностью установлены на ZFS, но было оставлено свободное пространство "на всякий случай". Там используется GPT "схема" со "стандартной" разбивкой на три партиции: freebsd-boot, freebsd-swap и freebsd-zfs. Свободное место было оставлено в конце диска. И вот, в один прекрасный момент захотелось использовать свободное место. Но создавать отдельную партицию не хотелось после успешных экспериментов по расширению пула ZFS.

После постановки задачи "как это сделать" очевидных решений найдено не было. Первое, что пришло на ум - поправить в таблице GPT размер партиции. Решил попробовать, подампил таблицу в файлы, поизучал формат... Решил посмотреть, что там в коде реализации. Оказалось, что "заготовка" базового метода resize уже имелась в коде класса. Только она ничего не делала, а возвращала ошибку ENOSYS.

Я связался с автором класса PART - Marcel Moolenaar. Обсудил с ним что и как лучше реализовать. После чего взялся за эксперименты. Что в итоге получилось, можно увидеть здесь. Ход работы можно проследить в perforce.

Если в кратце, то в начале пришлось заново вспомнить изучить для чего в дереве кода ядра используются файлы с расширением "*.m". Они применяются для создания подобия ООП в коде ядра. Как я уже упоминал ранее, структура класса PART интересна своей модульностью. Сам класс имеет базовые методы работы с партициями, а все детали реализации описываются в отдельных модулях схем. Так вот, в .m файлах описан программный "интерфейс" подобных модулей. Эти файлы обрабатываются awk скриптом во время компиляции ядра и генерируются файлы .c и .h.

Грубо говоря, благодаря им и создаётся иллюзия ООП. Хотя на мой взгляд всё довольно условно :) Итак, реализовав базовый алгоритм изменения размера в ядре и добавив новую команду в утилиту управления gpart, я добавил поддержку в GPT схему. Потестировал на md(4) дисках - вроде работает и даже не паникует :)
Решил попробовать на рабочей системе, попробовал - размер изменился, перезагрузился - пул "подхватил" свободное пространство и я счастлив :)

После этого добавил поддержку в оставшиеся схемы, немного потестировал на том же md(4) и вроде всё. Да, только в EBR не стал добавлять, там как-то не всё гладко в реализации.

Пример использования:
# gpart show md0
=>    34  409533  md0  GPT  (200M)
      34  204800    1  freebsd-zfs  (100M)
  204834  204733       - free -  (100M)

# gpart resize -s 150m -i 1 md0
md0p1 resized
# gpart show md0
=>    34  409533  md0  GPT  (200M)
      34  307200    1  freebsd-zfs  (150M)
  307234  102333       - free -  (50M)

# gpart resize -i 1 md0
md0p1 resized
# gpart show md0
=>    34  409533  md0  GPT  (200M)
      34  409533    1  freebsd-zfs  (200M)

У команды resize есть два параметра "-i index" и "-s size". Указание индекса обязательно, а вот размер может быть вычислен автоматически. Изменяться может только смещение конца партиции, смещение начала всегда остаётся неизменным.

И ещё важное замечание - изменяются только метаданные таблицы разделов, изменение размеров файловой системы нужно производить сторонними методами, например growfs для UFS. ZFS сама видит увеличение. Уменьшение разделов не запрещено и работает, но что на это скажет файловая система раздела - мне, честно говоря, не очень хочется узнавать :)

9 комментариев:

  1. доброго времени суток- а не подскажете:
    диск 40 гигов -
    свап и пул занимают 30 гигов (freebsd8.1)
    10 гигов не размеченной области!
    Как размеченную область добавить к пулу
    не используя Ваш патч! а то я так понял что он решает мою проблему

    ОтветитьУдалить
  2. Этот функционал уже включен в состав 9.0 и 8-STABLE, т.е. в 8.2-RELEASE оно тоже будет.
    Чтобы ответить на вопрос, мне нужно увидеть вывод `gpart show`.

    ОтветитьУдалить
  3. gpart show
    => 63 488394963 mirror/gm0 MBR (233G)
    63 488392002 1 freebsd [active] (233G)
    488392065 2961 - free - (1.4M)

    => 0 488392002 mirror/gm0s1 BSD (233G)
    0 4194304 1 freebsd-ufs (2.0G)
    4194304 3990849 2 freebsd-swap (1.9G)
    8185153 4194304 4 freebsd-ufs (2.0G)
    12379457 41943040 5 freebsd-ufs (20G)
    54322497 434069505 6 freebsd-ufs (207G)
    --
    df -h
    Filesystem Size Used Avail Capacity Mounted on
    /dev/mirror/gm0s1a 1.9G 169M 1.6G 9% /
    devfs 1.0K 1.0K 0B 100% /dev
    /dev/mirror/gm0s1d 1.9G 12K 1.8G 0% /tmp
    /dev/mirror/gm0s1e 19G 1.1G 17G 6% /usr
    /dev/mirror/gm0s1f 200G 388K 184G 0% /var

    А мне бы var отдать гигов 5, остальное на usr.. подскажите, как?

    ОтветитьУдалить
  4. такое изменение можно выполнить только при помощи бэкапа данных. Загрузившись с livecd вы можете удалить mirror/gm0s1f, изменить размер mirror/gm0s1e. Тут можно попробовать использовать growfs, либо заново пересоздать файловую систему. Далее создать новый /var и восстановить данные.

    ОтветитьУдалить
  5. Здравствуйте! Подскажите пожалуйста. На диске несколько основных разделов.
    Увеличил слайс FreeBSD на 100G, увеличил раздел freebsd-zfs на 100G, но ZFS не видит эти 100G.
    Возможно ли изменить размер ZFS без потери данных?
    # gpart show ada0s1
    => 0 419457087 ada0s1 BSD (200G)
    0 2097152 1 freebsd-ufs (1.0G)
    2097152 19922944 2 freebsd-swap (9.5G)
    22020096 397436991 4 freebsd-zfs (189G)

    # zpool list tank0
    NAME SIZE ALLOC FREE CAP DEDUP HEALTH ALTROOT
    tank0 89,5G 86,2G 3,30G 96% 1.00x ONLINE -

    # zpool history tank0
    History for 'tank0':
    2011-10-10.16:17:37 zpool create -m none -f tank0 /dev/ada0s1d
    2011-10-10.16:17:40 zfs set atime=off tank0
    2011-10-10.16:17:40 zfs set mountpoint=/mnt tank0
    2011-10-10.16:17:40 zfs set atime=off tank0
    2011-10-10.16:17:42 zfs create -p tank0/var
    2011-10-10.16:17:42 zfs set mountpoint=/mnt/var tank0/var
    2011-10-10.16:17:42 zfs set atime=off tank0/var
    2011-10-10.16:17:44 zfs create -p tank0/usr
    2011-10-10.16:17:44 zfs set mountpoint=/mnt/usr tank0/usr
    2011-10-10.16:17:49 zfs set atime=off tank0/usr
    2011-10-10.17:03:47 zfs set mountpoint=/usr tank0/usr
    2011-10-10.17:03:52 zfs set mountpoint=/var tank0/var
    2011-10-10.17:03:57 zfs set mountpoint=legacy tank0
    2012-02-17.20:21:41 zpool import tank0
    2012-02-17.20:22:56 zpool export tank0
    2012-02-17.20:23:09 zpool import tank0
    2012-02-17.17:08:30 zpool scrub tank0

    ОтветитьУдалить
    Ответы
    1. Судя по всему, пока что не реализована возможность автоматического определения увеличения провайдера для ZFS.
      Вам нужно загрузится, например с диска, поставить zpool set autoexpand=on и сделать export/import для пула.

      Удалить
  6. А как изменить раздел GTP, если зеркало перенесли на больший диск?

    ОтветитьУдалить
  7. $ gpart show
    => 255 234439095 ad0 MBR (112G)
    255 234439095 - free - (112G)

    => 255 234441390 ad1 MBR (112G)
    255 234441390 - free - (112G)

    => 0 234438561 ad0s1 BSD (112G)
    0 1048576 2 freebsd-swap (512M)
    1048576 2097152 4 freebsd-ufs (1.0G)
    3145728 4194304 1 freebsd-ufs (2.0G)
    7340032 8388608 5 freebsd-ufs (4.0G)
    15728640 4194304 6 freebsd-ufs (2.0G)
    19922944 4194304 7 freebsd-ufs (2.0G)
    24117248 210321313 8 freebsd-ufs (100G)

    => 0 234441585 ad1s1 BSD (112G)
    0 234441585 4 freebsd-ufs (112G)

    $ df -h
    Filesystem Size Used Avail Capacity Mounted on
    /dev/ad0s1a 1.9G 210M 1.6G 12% /
    devfs 1.0K 1.0K 0B 100% /dev
    /dev/ad0s1h 97G 86G 3.2G 96% /data
    /dev/ad0s1g 1.9G 1.9M 1.8G 0% /home
    /dev/ad1s1d 108G 95G 4.5G 95% /inst
    /dev/ad0s1d 989M 24K 910M 0% /tmp
    /dev/ad0s1e 3.9G 3.9G -313M 109% /usr
    /dev/ad0s1f 1.9G 140M 1.6G 8% /var
    $
    Подскажите как перенести 1G c /data на /usr без потери данных

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

    ОтветитьУдалить