АйТи Фреш
Главная / Статьи / Серверы и инфраструктура
Серверы и инфраструктура

lvextend отработал успешно, но df показывает старый размер: какой слой хранилища вы забыли

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~21 мин чтения
Слои хранилища LVM: том расширен, а файловая система наверху осталась старого размера — df не изменился
lvextend растягивает контейнер, а df показывает содержимое — расширять нужно оба.

Если lvextend прошёл без ошибок, а df показывает старый размер, вы расширили логический том, но не файловую систему на нём. Лечится одной командой — xfs_growfs или resize2fs, онлайн. Ниже разбираю, из каких слоёв состоит место на диске, как за минуту найти застрявший слой и в каком порядке расширять.

Почему lvextend не меняет df: шесть слоёв вместо одного

Звонок в девять утра: «Расширили диск, всё сделали по инструкции, lvextend отработал без ошибок — а база всё равно падает». Подключаюсь, смотрю df -h — те же 150 гигабайт, что и вчера. Смотрю lvs — 250. Обе команды говорят правду, просто о разных вещах. Это непонимание я вижу у администраторов чаще любой другой ошибки в LVM, и особенно больно оно бьёт по серверам 1С на Linux с PostgreSQL, где база растёт незаметно, а падает мгновенно.

«Место на диске» в схеме с LVM — это не одна величина, а стопка вложенных друг в друга сущностей. Снизу вверх: блочное устройство (виртуальный диск или LUN), поверх него таблица разделов, поверх раздела — физический том LVM (PV), PV входит в группу томов (VG), из свободных экстентов VG нарезается логический том (LV), и уже на LV лежит файловая система. Шесть уровней. И каждый из них имеет собственный размер, который меняется собственной командой. Ни один из них не растёт автоматически вслед за соседом.

lvextend работает ровно с одним уровнем — он забирает свободные физические экстенты из VG и отдаёт их логическому тому. Всё. Ему нет дела до того, что лежит внутри LV: файловая система, LUKS-контейнер, сырой раздел под Oracle ASM или вообще ничего. Поэтому сообщение «Logical volume successfully resized» означает буквально: том стал больше. Оно ничего не обещает про файловую систему. А df показывает именно файловую систему — её суперблок, её счётчик блоков. Файловая система, которую никто не трогал, честно рапортует старый размер.

Симметричная ошибка на нижнем уровне: человек расширил виртуальный диск в vSphere или Proxmox, побежал делать lvextend -l +100%FREE и получил «Insufficient free space». Потому что новые гигабайты появились у блочного устройства, но ядро об этом не знает, раздел остался прежним, PV не переразмечен, и свободных экстентов в VG как не было, так и нет. Тот же самый разрыв между слоями, просто с другой стороны.

Запомните формулировку, которая экономит часы: lvextend меняет размер контейнера, а df показывает размер содержимого. Успешный lvextend без последующего расширения ФС — это ровно половина работы, и именно эту половину чаще всего забывают доделать.
Памятка: Почему lvextend не меняет df: шесть слоёв вместо одного — схема
Памятка: Почему lvextend не меняет df: шесть слоёв вместо одного. Открыть схему в полном размере
Схема слоёв LVM от диска до файловой системы и команда расширения для каждого слоя
Каждый слой меняется своей командой, и ни один не растёт вслед за соседом сам.

Кейс: аквариумный салон, 1С на PostgreSQL и 100 гигабайт, которых не было

Клиент — аквариумный салон «Коралловый риф», 26 рабочих мест: два торговых зала, склад живого товара и кормов, сервисная служба, которая обслуживает аквариумы в офисах и ресторанах. Учёт — 1С:Розница и 1С:Бухгалтерия на PostgreSQL 15, сервер — виртуальная машина с Debian 12 на Proxmox. Каталог /var/lib/postgresql жил на отдельном LV в 150 ГБ с файловой системой XFS, PV был создан на всём втором виртуальном диске /dev/sdb без таблицы разделов. К концу года база и архив WAL разрослись, мониторинг начал сигналить на 90 %, и администратор клиента получил задачу «добавить места».

Он увеличил виртуальный диск в Proxmox со 150 до 250 ГБ, выполнил на сервере rescan устройства, pvresize /dev/sdb и lvextend -l +100%FREE /dev/vgdata/pgdata, увидел «Logical volume successfully resized» и закрыл заявку. Шаг с файловой системой в найденной им инструкции просто отсутствовал. Через двое суток, в субботу — самый загруженный день салона, — PostgreSQL остановился с could not extend file ... No space left on device, кассы перестали проводить чеки. Я подключился и увидел картину, которая с тех пор служит мне учебным пособием.

# LVM уверен, что всё хорошо
$ sudo lvs vgdata/pgdata
  LV     VG     Attr       LSize
  pgdata vgdata -wi-ao---- <250.00g

# файловая система живёт в прошлом
$ df -hT /var/lib/postgresql
Filesystem                Type  Size  Used Avail Use% Mounted on
/dev/mapper/vgdata-pgdata xfs   150G  150G   20K 100% /var/lib/postgresql

# XFS знает только о старых 150 ГиБ
$ sudo xfs_info /var/lib/postgresql | head -3
meta-data=/dev/mapper/vgdata-pgdata isize=512  agcount=4, agsize=9830400 blks
         =                         sectsz=512  attr=2, projid32bit=1
data     =                         bsize=4096  blocks=39321600, imaxpct=25

Лечение заняло одиннадцать секунд: xfs_growfs /var/lib/postgresql. XFS расширяется только на смонтированной ФС, так что базу даже не пришлось останавливать — PostgreSQL сам продолжил работу, как только появилось место, кассы ожили через пару минут. Весь простой — около сорока минут, из которых тридцать ушли на то, чтобы до меня дозвонились. Потом мы разложили процедуру в чек-лист, добавили в Zabbix триггер на расхождение размера LV и размера ФС (lvs --units b -o lv_size против df -B1 --output=size) и договорились, что расширение диска — не «одна команда», а последовательность из пяти. За следующие девять месяцев повторов не было.

Пока файловая система не расширена, лишние экстенты LV лежат мёртвым грузом, но LVM считает их занятыми. Место в VG вы уже потратили, а места в приложении так и не получили — худший из промежуточных статусов.
lvextend отработал успешно, но df показывает старый размер: какой слой хранилища вы забыли — схема
Схема к статье. Открыть схему в полном размере

Диагностика за минуту: три команды, которые показывают, на каком слое вы застряли

Когда прилетает «место добавили, а его нет», я не гадаю и не читаю чужие логи. Я выполняю три команды подряд и по расхождению цифр сразу вижу точку разрыва. Это занимает меньше минуты и работает на любом дистрибутиве — RHEL, Debian, Astra Linux, неважно.

# 1. Что видит ядро: диски, разделы, LV, точки монтирования
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT

# 2. Что видит LVM: размер PV, свободное место VG, размер LV
sudo pvs; sudo vgs; sudo lvs

# 3. Что видит файловая система
df -hT

Читаются они снизу вверх по стопке слоёв. Если lsblk показывает диск старого размера — вы не сделали rescan на стороне ОС (или вообще не расширили диск в гипервизоре, бывает и такое). Если диск нового размера, а раздел старого — не хватает growpart. Если раздел вырос, а pvs показывает прежний PSize — забыт pvresize. Если vgs показывает VFree в сотни гигабайт, а LSize не изменился — не сделан lvextend. И, наконец, если LSize вырос, а df стоит на месте — вы ровно в той ситуации, ради которой написана эта статья: не расширена файловая система. Если же все цифры сошлись, а свободное место в VG кончилось, остаётся добавить новый диск через vgextend — а старый при необходимости потом вывести из LVM без размонтирования.

Отдельно советую сразу проверять, ту ли ФС вы вообще смотрите. Классика жанра: на сервере два похожих тома, vgdata/data и vgdata/data_archive, админ расширил первый, а приложение пишет во второй, смонтированный через bind-mount из другого каталога. Команда findmnt -T /путь/к/каталогу показывает реальный источник монтирования и снимает вопрос за секунду. Ещё чаще это встречается с контейнерами: внутри контейнера df вообще может показывать overlay-слой, никак не связанный с вашим LV.

Не начинайте с `df`. Начинайте с `lsblk`. Диагностика снизу вверх сразу отсекает половину гипотез, а диагностика сверху вниз заставляет вас угадывать.
Дерево решений диагностики LVM: по lsblk, pvs, vgs, lvs и df найти слой, где застряло место
Диагностика снизу вверх за минуту показывает, какой шаг пропущен.

Правильный порядок: от виртуального диска до файловой системы

Вот последовательность, которую я держу в чек-листе и по которой работаю на любом Linux-сервере с LVM. Она предполагает, что диск уже расширен в гипервизоре или СХД. Показываю на PV, лежащем на разделе /dev/sdb1, — это более сложный и более частый вариант. Если PV создан на диске целиком, как у «Кораллового рифа», шаг 2 просто пропускается. Для дисков virtio-blk (/dev/vda, /dev/vdb) rescan обычно не нужен: ядро получает новый размер от гипервизора само, проверьте lsblk.

# 1. Показать ядру, что устройство подросло (SCSI/virtio-scsi)
echo 1 | sudo tee /sys/class/block/sdb/device/rescan
# или из пакета sg3-utils: sudo rescan-scsi-bus.sh -s
lsblk /dev/sdb

# 2. Растянуть раздел на новое место (пакет cloud-guest-utils / cloud-utils-growpart)
sudo growpart /dev/sdb 1

# 3. Забрать новый размер раздела в физический том LVM
sudo pvresize /dev/sdb1
sudo vgs           # здесь должен появиться VFree

# 4. Отдать место логическому тому (явный размер, не всё)
sudo lvextend -L +80G /dev/vgdata/pgdata

# 5. Расширить файловую систему
sudo xfs_growfs /var/lib/postgresql     # XFS: по точке монтирования
# sudo resize2fs /dev/vgdata/pgdata     # ext4: по устройству

Про growpart скажу отдельно, потому что тут людей пугают зря. Да, вы редактируете таблицу разделов на живом диске с примонтированной ФС. Нет, это не страшно — при условии, что вы увеличиваете последний раздел и не двигаете его начало. growpart из пакета cloud-utils написан именно под этот сценарий, он же корректно переносит резервную копию GPT в новый конец диска. Ручные пляски с fdisk (удалить раздел, создать заново с тем же стартовым сектором) тоже работают, но там ошибиться на один сектор — и вы потеряли файловую систему. Я такое делаю только когда growpart недоступен.

Про -l +100%FREE тоже есть нюанс. Проценты в LVM считаются от свободного места группы томов, а не от свободных блоков внутри файловой системы. Если в VG живут снимки, тонкие пулы или вы хотели оставить запас под соседний том, +100%FREE съест всё подчистую и не спросит. На боевых серверах я почти всегда пишу явный размер — lvextend -L +80G, оставляя 10–15 % VG свободными как манёвр на случай аварии, в том числе под снимок перед обновлением: как он ведёт себя при нехватке места, я разбирал в статье про переполненный снимок LVM. Вернуть место обратно из XFS штатно не получится: xfs_growfs умеет уменьшать только последнюю группу выделения, и то в экспериментальном режиме, для практики это не вариант.

Перед `growpart` на боевом сервере сделайте снимок виртуальной машины или хотя бы `sfdisk -d /dev/sdb > /root/sdb.parttable`. Расширение LV и ФС практически безопасно, а правка таблицы разделов — единственный шаг в этой цепочке, который при ошибке стоит вам данных.
Порядок действий: Правильный порядок: от виртуального диска до файловой системы — схема
Порядок действий: Правильный порядок: от виртуального диска до файловой системы. Открыть схему в полном размере

Флаг -r, --fs resize и почему я всё равно пишу два шага

У lvextend есть ключ, который закрывает ровно эту боль: -r (он же --resizefs). Команда lvextend -r -L +80G /dev/vgdata/pgdata расширит и том, и файловую систему одним вызовом, и df покажет новую цифру сразу. Для XFS расширение идёт онлайн, размонтировать ничего не нужно. Без -r lvextend файловую систему не трогает вообще — именно это и случилось у «Кораллового рифа».

Механика под капотом поменялась, и это важно понимать. До lvm2 2.03.17 -r вызывал внешний скрипт fsadm, который умеет ext2/3/4, ReiserFS и XFS и не умеет btrfs. Именно такая версия, 2.03.16, стоит в Debian 12 и Ubuntu 24.04 — новых ключей там нет. В Debian 13 уже lvm2 2.03.31, и там появились --fs и --fsmode. --fs resize вызывает штатную утилиту конкретной ФС, и по man-странице -r теперь эквивалентен именно ему; --fs resize_fsadm — старый путь через fsadm, помеченный как устаревший; --fs ignore — изменить LV, не глядя на файловую систему. --fsmode определяет, можно ли LVM самому монтировать и размонтировать том: manage — можно, с попыткой вернуть исходное состояние; nochange — нельзя, и команда упадёт, если без этого не обойтись; offline — размонтировать и менять размер на отмонтированной ФС. Узнать свою версию — lvm version.

# lvm2 2.03.17 и новее (Debian 13 и др.)
sudo lvextend --fs resize --fsmode nochange -L +80G /dev/vgdata/pgdata

# универсальный вариант, работает и на старых версиях
sudo lvextend -r -L +80G /dev/vgdata/pgdata

# для btrfs -r не поможет, ФС расширяется своей командой
sudo lvextend -L +80G /dev/vgdata/data
sudo btrfs filesystem resize max /mnt/data

Для ручной работы на живом сервере я указываю --fsmode nochange: если LVM вдруг решит, что том надо размонтировать, пусть лучше упадёт, чем уронит базу. И теперь честно: сам я на боевых серверах чаще пишу два шага вместо одного. Не потому, что -r плохой — он хороший и почти всегда работает идеально. А потому, что при неудаче он даёт менее понятный вывод: том уже расширен, ФС нет, а в консоли одна общая строка ошибки от fsadm, по которой не сразу видно, на чём именно споткнулось. Когда шаги разделены, lvextend и xfs_growfs рапортуют отдельно, и в логе заявки видно, что прошло, а что нет. Для скриптов и автоматизации -r — правильный выбор, для ручной работы под нагрузкой я предпочитаю видеть каждый шаг. Это вопрос вкуса, и я не стану утверждать, что мой подход единственно верный.

Отдельная ловушка — уменьшение. lvreduce -r для ext4 сначала ужмёт файловую систему (офлайн), потом том, и это сработает. Для XFS штатного пути нет: единственный способ получить меньший размер — выгрузить данные, пересоздать ФС и загрузить обратно. Без -r lvreduce в новых версиях по умолчанию проверяет, не отрежет ли он занятые данные (--fs checksize), а в старых — отрежет молча, так что порядок «сначала ФС, потом том» надо держать в голове всегда.

Не используйте `-r` вслепую на томах, отданных приложению как сырое блочное устройство (Oracle ASM, диски виртуальных машин поверх LV). Там LVM нечего расширять выше тома, а правильный ключ в новых версиях — `--fs ignore`.

df уже показывает новый размер, а места всё равно нет

Бывает и обратная история, и она честно относится к той же боли: расширили всё правильно, df рисует свежие гигабайты с кучей свободного — а приложение продолжает ругаться на нехватку места. Значит, вы уперлись не в блоки. Частых причин четыре, и проверяются они за пару минут.

Первая — закончились inode. Файловая система хранит метаданные о файлах в отдельном пуле фиксированного размера, заданном при mkfs. Если на томе миллионы мелких файлов (кэш, сессии PHP, почтовый maildir, спул 1С), inode кончаются задолго до блоков, и ядро отдаёт ровно тот же ENOSPC. Смотрите df -i. У XFS ситуация мягче — inode выделяются динамически, но упираются в параметр imaxpct; у ext4 пул жёсткий и увеличить его без пересоздания ФС нельзя. Это ещё один аргумент за XFS под нагрузками с миллионами файлов. Как это выглядит на практике и чем лечится, я подробно разбирал в статье про исчерпание inode на ext4.

Вторая — удалённые, но открытые файлы. Кто-то удалил старый лог на 20 ГБ, а процесс держит на него дескриптор — место не освобождается до перезапуска процесса. Ищется командой sudo lsof +L1, там будет столбец NLINK со значением 0. Третья — зарезервированные блоки: ext4 по умолчанию прячет 5 % тома под root, и на терабайтном разделе это около пятидесяти гигабайт, недоступных обычному приложению. Лечится sudo tune2fs -m 1 /dev/vgdata/data, для тома с данными (не системного) резерв в 5 % — чистое расточительство. Похожая история бывает и с системным журналом: journalctl --vacuum-size отработал, а место не вернулось, потому что его держат совсем другие файлы.

df -i /var/lib/pgsql          # закончились ли inode
sudo lsof +L1                 # удалённые файлы, удерживаемые процессами
sudo tune2fs -l /dev/vgdata/data | grep -i reserved   # резерв ext4
sudo lvs -o+data_percent,metadata_percent             # заполнение thin pool

Четвёртая и самая неприятная — тонкие тома. Если LV нарезан из thin pool, его собственный размер вам ничего не говорит: физическое место выделяется по мере записи и берётся из пула. Пул может быть переполнен, притом что и lvs и df показывают приличные цифры. Отдельно следите за метаданными пула: их переполнение переводит пул в режим только для чтения и лечится куда сложнее, чем нехватка данных. Колонки Data% и Meta% в выводе lvs — то, что должно быть в мониторинге, а не только использование ФС.

На thin pool расширение обычного тонкого LV ничего не даёт, пока не расширен сам пул: `lvextend -L +200G vgdata/thinpool`, метаданные — `lvextend --poolmetadatasize +1G vgdata/thinpool`. И заведите отдельный триггер на метаданные пула — переполнение Meta% ломает пул жёстче, чем переполнение Data%.
Четыре причины No space left on device при свободном месте в df: inode, удалённые файлы, резерв ext4, thin pool
Если df показывает свободное место, упираетесь уже не в блоки — проверьте эти четыре вещи.

Что делать прямо сейчас, а на что можно спокойно забить

Если вы читаете это в аварии — порядок такой. Выполните lsblk, vgs, lvs, df -hT и сравните цифры сверху вниз. Найдите слой, где размер перестал совпадать. Доделайте недостающий шаг: pvresize, lvextend или xfs_growfs/resize2fs. Расширение XFS и ext4 идёт онлайн, останавливать сервисы не нужно. Обычно с момента подключения до нормального df проходит меньше пяти минут — если, конечно, вам есть откуда взять место.

Если авария уже позади, вложитесь в две вещи. Первая: мониторинг не только процента заполнения ФС, но и свободного места VG. Классический сценарий у моих клиентов — мониторинг сигналит на 90 % занятости тома, админ идёт расширять, а в VG свободных экстентов ноль, потому что при установке всё раздали под корень. Знать об этом надо за месяц до, а не в ночь на понедельник. Вторая: чек-лист расширения в вики, с командами под вашу разметку. Пять строк текста, которые снимают 90 % повторных заявок.

А на что можно забить со спокойной душой. Не переживайте по поводу «онлайн-расширения на живой базе» — это штатная операция, XFS и ext4 растут на смонтированной ФС годами и стабильно, окно обслуживания под это не нужно. Не гонитесь за идеальной разметкой отдельных томов под каждый каталог: для сервера на 26 рабочих мест, как у «Кораллового рифа», вынесенных /var и данных приложения более чем достаточно, дробление на восемь LV даёт вам восемь мест, где может кончиться место. И не бойтесь -r — да, я сам пишу шаги раздельно, но это привычка, а не требование безопасности.

Единственное, к чему я отношусь всерьёз, — резерв в группе томов. Оставленные незанятыми 10–15 % VG стоят вам ровно ничего, а в момент, когда база растёт быстрее прогноза или нужно срочно снять снапшот перед обновлением, они спасают вечер. Отдать всё до последнего экстента командой +100%FREE — самое частое решение и самое частое сожаление. У «Кораллового рифа» после того случая мы увеличили диск ещё на 100 ГБ и держим их свободными в VG: при нынешнем росте базы это запас примерно на год, и расширение теперь плановая пятиминутная задача, а не субботний пожар.

Самая дорогая ошибка в этой теме — не забытый `xfs_growfs`, а раздача всего VG под завязку на этапе установки. Забытую команду вы доделаете за минуту, а вот найти место в полностью занятой группе томов посреди ночи уже не получится.
Порядок действий: Что делать прямо сейчас, а на что можно спокойно забить — схема
Порядок действий: Что делать прямо сейчас, а на что можно спокойно забить. Открыть схему в полном размере

Частые вопросы

lvextend отработал, а df показывает старый размер. Данные не потерялись?

Нет, данные в полном порядке. Файловая система просто не знает, что том под ней стал больше, и продолжает работать в старых границах. Выполните `xfs_growfs /точка/монтирования` для XFS или `resize2fs /dev/vg/lv` для ext4 — размер в df обновится сразу, останавливать сервисы не нужно.

Можно ли расширять файловую систему на работающей базе, не останавливая сервис?

Да. И XFS, и ext4 расширяются онлайн, на смонтированной файловой системе. XFS вообще умеет только онлайн-расширение — команда `xfs_growfs` требует, чтобы ФС была примонтирована. На нагруженных серверах операция занимает секунды и не вызывает заметной просадки. Окно обслуживания нужно только на шаг с правкой таблицы разделов, и то скорее из осторожности.

Почему lvextend пишет «Insufficient free space», хотя я увеличил диск в гипервизоре?

Потому что новое место застряло на нижнем слое. Ядру нужно сообщить о росте устройства (`echo 1 > /sys/class/block/sdX/device/rescan` или `rescan-scsi-bus.sh -s`), затем растянуть раздел (`growpart /dev/sdX 1`, если PV на разделе), затем забрать новый размер в LVM (`pvresize`). Только после этого в `vgs` появится VFree.

Чем -r отличается от отдельного вызова xfs_growfs?

Результат тот же, разница в диагностике. В lvm2 до 2.03.17 (Debian 12, Ubuntu 24.04) `-r` вызывает fsadm, в новых эквивалентен `--fs resize` и вызывает штатную утилиту ФС. Отдельные команды дают более понятный вывод при ошибке: видно, что LV расширился, а ФС нет. Для скриптов удобнее `-r`, для ручной работы я пишу два шага.

Расширил всё правильно, df показывает свободное место, а приложение всё равно пишет No space left. Что дальше?

Проверьте четыре вещи: `df -i` (закончились inode), `lsof +L1` (удалённые файлы удерживает живой процесс), резерв 5 % у ext4 (`tune2fs -m 1` для томов с данными) и заполнение тонкого пула (`lvs -o+data_percent,metadata_percent`). В девяти случаях из десяти это inode или удалённый лог, который держит незакрытый дескриптор.

Можно ли потом уменьшить том обратно, если расширил лишнего?

Для ext4 — да, офлайн: размонтировать, проверить `e2fsck -f`, `resize2fs` до нужного размера, затем `lvreduce` (или всё сразу через `lvreduce -r`). Для XFS штатного уменьшения нет: выгрузка данных, пересоздание ФС меньшего размера и загрузка обратно. Поэтому на XFS я задаю размер явно, а не `+100 %FREE`.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи