Как временно расширить ZFS-пул с помощью zvol из другого пула

Иногда ZFS-пул оказывается заполнен почти полностью, но переносить данные на другой файловый раздел неудобно или слишком долго.

Было два независимых пула:

zpool list

NAME    SIZE  ALLOC   FREE  FRAG  CAP  HEALTH
db     11.7T  8.99T  2.71T   18%  76%  ONLINE
limon  79.5G  77.0G  2.46G   90%  96%  ONLINE

Пул limon закончился, а в пуле db оставалось несколько терабайт свободного пространства.

Требовалось временно дать пулу limon около 10 ГБ, очистить логи и затем вернуть конфигурацию в исходное состояние.

Почему нельзя просто передать свободное место?

Свободное пространство принадлежит конкретному ZFS-пулу. Датасет одного пула не может непосредственно использовать место из другого пула.

Топология исходного пула

Пул limon состоял из одного раздела:

zpool status limon

pool: limon
state: ONLINE
config:

    NAME        STATE     READ WRITE CKSUM
    limon       ONLINE       0     0     0
      sdd1      ONLINE       0     0     0

Для последующего удаления временного vdev необходимо проверить поддержку функции device_removal:

zpool get feature@device_removal limon

В моём случае функция была включена:

NAME   PROPERTY                VALUE    SOURCE
limon  feature@device_removal  enabled  local

Также необходимо определить фактическое значение ashift существующего vdev.

Команда:

zpool get ashift limon

может показать:

limon  ashift  0  default

Значение 0 означает автоматический выбор для новых устройств и не показывает фактический ashift уже существующего vdev.

Реальное значение можно получить через zdb:

zdb -C limon | grep -E 'path|ashift'

Результат:

path: '/dev/sdd1'
phys_path: 'acpi-VMBUS:01-vmbus-3d4511ba2bac43a19298b9d3bddf7b27-lun-2'
ashift: 12

Таким образом, временный vdev тоже нужно добавлять с ashift=12.

Важное предупреждение

Описанный способ создаёт зависимость одного ZFS-пула от другого.

Пока временный zvol входит в пул limon:

  • пул db нельзя экспортировать;
  • zvol нельзя удалить;
  • сервер нельзя загружать без доступного пула db;
  • потеря пула db может привести к потере всего пула limon
    Это аварийная временная мера, а не постоянная архитектура хранения.

Создание временного zvol

Чтобы не повторять изменяемые значения в командах, зададим переменные:

POOL_SOURCE="db"
POOL_TARGET="limon"
ZVOL_NAME="limon-temp-vdev"
ZVOL_SIZE="10G"
ZVOL_DATASET="${POOL_SOURCE}/${ZVOL_NAME}"
ZVOL_DEVICE="/dev/zvol/${ZVOL_DATASET}"
ASHIFT="12"
VOLBLOCKSIZE="16K"

Создаём обычный, неразреженный zvol:

zfs create -V "${ZVOL_SIZE}" -b "${VOLBLOCKSIZE}" -o compression=off "${ZVOL_DATASET}"

Проверяем созданный zvol:

zfs get volsize,volblocksize,refreservation,compression "${ZVOL_DATASET}"

Проверяем наличие блочного устройства:

udevadm settle
ls -l "${ZVOL_DEVICE}"
blockdev --getsize64 "${ZVOL_DEVICE}"

У обычного zvol параметр refreservation должен быть примерно равен его размеру. Это гарантирует, что необходимые 10 ГБ действительно зарезервированы в пуле db.

Проверка добавления без изменения пула

Сначала выполняем пробный запуск:

zpool add -n -o ashift="${ASHIFT}" "${POOL_TARGET}" "${ZVOL_DEVICE}"

В предполагаемой конфигурации исходный диск и временный zvol должны находиться на одном уровне:

limon
sdd1
/dev/zvol/db/limon-temp-vdev

Добавление временного пространства

Если пробная проверка не показывает ошибок, добавляем zvol:

zpool add -o ashift="${ASHIFT}" "${POOL_TARGET}" "${ZVOL_DEVICE}"

После этого проверяем состояние:

zpool status -P "${POOL_TARGET}"zpool list "${POOL_TARGET}"
zfs list "${POOL_TARGET}"

Дополнительно проверяем ashift обоих vdev:

zdb -C "${POOL_TARGET}" | grep -E 'path|ashift'

Оба top-level vdev должны иметь ashift=12. Разный ashift может помешать последующему удалению временного устройства.

После добавления zvol пул limon получит немного меньше 10 ГБ полезного пространства из-за внутренних накладных расходов ZFS.

Удаление временного vdev

Сначала проверяем возможность удаления:

zpool remove -n "${POOL_TARGET}" "${ZVOL_DEVICE}"

Параметр -n не выполняет полноценную симуляцию переноса данных. Он используется для оценки параметров операции, включая необходимый объём памяти для таблиц перенаправления.

Если ошибок нет, запускаем удаление с ожиданием завершения:

zpool remove -w "${POOL_TARGET}" "${ZVOL_DEVICE}"

Во время удаления ZFS переносит блоки с временного zvol обратно на исходный диск sdd1.

За процессом можно наблюдать в другом терминале:

watch -n 5 "zpool status ${POOL_TARGET}; zpool list ${POOL_TARGET}"

До полного завершения операции нельзя:

  • уничтожать zvol;
  • экспортировать пул db;
  • отключать устройство;
  • перезагружать систему без необходимости.

После успешного удаления проверяем, что в пуле остался только исходный vdev:

zpool status -P "${POOL_TARGET}"

В конфигурации должен снова отображаться только sdd1.

Удаление временного zvol

Только после успешного завершения zpool remove можно уничтожить zvol:

zfs destroy "${ZVOL_DATASET}"

Финальная проверка:

zpool status "${POOL_TARGET}"
zpool list "${POOL_TARGET}"
zfs list "${POOL_SOURCE}" "${POOL_TARGET}"
Поделиться
Отправить