Что значит ошибка Too many links / EMLINK
Сообщение Too many links (errno EMLINK) в Linux почти всегда означает одно: вы пытаетесь создать ещё одну жёсткую ссылку (hard link) на inode, у которого уже достигнут предел счётчика ссылок (inode link count).
В отличие от проблем с правами, «слишком длинного пути» или переполненного диска, это именно ограничение файловой системы на количество имён, указывающих на один и тот же inode.
Типовой сценарий из продакшена: деплой делает «атомарные» релизы через hard link (или через snapshot-папки), чтобы не копировать гигабайты. На очередном прогоне CI всё внезапно падает с ln: failed to create hard link ...: Too many links или аналогичной ошибкой в cp/rsync/tar.
Важно: EMLINK — это не про количество файлов в каталоге и не про symlink. Это про счётчик жёстких ссылок на конкретный inode.
Быстрый ликбез: hard link vs symlink и где здесь лимит
Hard link — это ещё одно имя для того же inode (того же файла). Данные на диске общие: меняете файл по одному имени — изменения видны по всем именам, потому что inode один.
Symlink — это отдельный маленький файл-указатель на путь. У symlink нет общего inode с целью, поэтому он не упирается в hardlink-лимит, но может «отваливаться» при перемещениях и требует аккуратности со структурой путей.
Ограничение, о которое вы бьётесь, — максимальное число hard links на один inode. На практике чаще всего встречается:
- ext4: типичный лимит жёстких ссылок на файл около 65 535 (в логах/обсуждениях часто называют «ext4 hlink limit»).
- XFS: в большинстве случаев лимит «на бумаге» гораздо выше, но реальная проблема всё равно может проявляться как EMLINK (в зависимости от версии ядра/утилит и сценария), либо как сопутствующие сбои в инструментах, которые пытаются переносить/упаковывать дерево с большим количеством hard links.
Отдельная деталь: у каталогов тоже есть link count (из-за . и записей .. в подкаталогах). Но классический EMLINK в деплое почти всегда относится к файлам, а не к каталогам.

Почему это всплывает в CI/deploy: rsync --link-dest, cp -al и «релизы»
Почти всегда проблема не в «случайной ошибке ФС», а в схеме, которая многократно переиспользует один и тот же inode.
1) rsync --link-dest
Опция --link-dest делает «инкрементальные» копии: новые/изменённые файлы копируются, а неизменённые — связываются hard link’ом на файлы из базового каталога. Это экономит место и время, но увеличивает link count у популярных файлов.
Если вы много раз делаете инкремент в один и тот же «эталон» (или у вас цепочка, где один и тот же файл постоянно переиспользуется), то один «топовый» файл может набрать десятки тысяч ссылок. Частые кандидаты — одинаковые vendor-бандлы, зависимости, статические ассеты, сборочные артефакты.
2) cp -al
cp -al SRC DST создаёт дерево каталогов, где файлы — hard links на исходные. Это популярно в «release-based deploy» (папки releases/2026-...), чтобы быстро создать новый релиз.
Если вы храните сотни/тысячи релизов и каждый раз «линкуете» один и тот же набор файлов, hardlink-лимит становится вопросом времени.
3) Архивы и бэкапы: hard links внутри tar
tar умеет сохранять hard links внутри архива. При распаковке он попытается восстановить hard links — и если лимит достигнут, получите EMLINK во время распаковки/восстановления.
Особенно неприятно это проявляется в бэкапах, которые «кажутся обычными»: вы ожидали, что там просто файлы, а внутри оказалась сетка hard links (например, бэкап делали тем же rsync --link-dest или с rsync -H).
Как диагностировать: где именно набрался лимит ссылок
Задача диагностики — найти inode с большим link count и понять, какой процесс размножает ссылки.
Шаг 1. Найти файлы с большим числом ссылок
find умеет фильтровать по количеству hard links:
find /path/to/releases -xdev -type f -links +1000 -printf '%n %p\n' | sort -nr | head
Здесь %n — это inode link count. Порог +1000 поднимайте, если дерево большое.
Шаг 2. Убедиться, что это один inode
Посмотрите inode и число ссылок:
stat -c 'inode=%i links=%h path=%n' /path/to/suspect/file
Чтобы найти другие имена того же inode в пределах файловой системы, ищите по inode:
inode=$(stat -c '%i' /path/to/suspect/file); find /path/to/releases -xdev -inum "$inode" -print | head
Если вывод огромный — вы нашли «размноженный» inode и понимаете, почему достигли лимита.
Шаг 3. Поймать источник создания hard links
В CI источник обычно виден по логу команд (cp -al, rsync --link-dest, rsync -H, распаковка архива). На живой системе полезно:
- пробежаться поиском по деплой-скриптам и job’ам CI на предмет флагов про hard links;
- проверить политику хранения релизов/снимков: «хранить бесконечно» почти гарантированно приведёт к EMLINK.
Если вы используете дисковые квоты или алерты по ресурсам, полезно также мониторить аномально высокий link count в релизных/бэкапных деревьях. См. практику в статье про квоты и алерты на ext4/XFS.
Чем ext4 отличается от XFS в контексте hardlink limit
ext4 — самый предсказуемый случай: на обычных настройках вы упираетесь в лимит порядка 65k hard links на inode. Это ограничение реализации файловой системы, и «подкрутить sysctl» тут нельзя.
XFS обычно лучше справляется с большими деревьями и метаданными, но это не означает «можно бездумно плодить hard links». В реальных пайплайнах часто бывает так:
- на ext4 вы падаете «быстро и честно» с EMLINK;
- на XFS ошибка проявляется позже или в другом месте (например, при переносе/архивации/восстановлении), потому что схема в целом становится сложной и хрупкой.
Практический вывод: если схема деплоя/бэкапа концептуально «размножает один inode тысячами имён», лучше исправлять схему, а не надеяться на конкретную ФС. Если выбираете ФС под VDS и хотите понимать, где сильные стороны ext4 и XFS, полезно сравнение в материале ext4 vs XFS для VDS и тюнинг под нагрузку.
Рабочие обходы и исправления (по приоритету)
1) Ограничить количество релизов/снапшотов
Самый простой и часто самый правильный фикс: хранить ограниченное число релизов (например, 10–30) и чистить старые. Тогда inode link count не растёт бесконечно.
Проверьте, есть ли у вас:
- папка
releases/с сотнями каталогов; - инкрементальные бэкапы
rsync --link-destбез ротации; - сборочные артефакты, которые «линкуются» в каждый релиз.
2) Не hardlink’ать «тяжёлые» каталоги: vendor/node_modules/build
Частая ошибка — делать hardlink всего дерева проекта, включая зависимости. Но зависимости обычно можно доставлять иначе:
- собирать артефакт (например, tar.gz) один раз и раскатывать как обычную копию без hard links;
- кешировать зависимости в CI, но на сервер деплоя выкладывать «готовый результат»;
- держать зависимости вне релизов и подключать через symlink на общий каталог (только если у вас хорошо контролируются версии и совместимость).
Да, это может добавить времени на деплой, но убирает класс ошибок EMLINK целиком.
3) Настроить rsync --link-dest так, чтобы база не была «вечной»
Если вы используете rsync --link-dest для бэкапов, то типовой паттерн — «сегодняшний» каталог как полноценный снимок, но фактически он состоит из hard links на «вчерашний». Важно, чтобы цепочка не опиралась на один и тот же неизменный inode годами.
Практичные приёмы:
- ротация (daily/weekly/monthly) с удалением старых снимков;
- периодический «полный» снимок без hard links (дороже по месту, но снимает накопление ссылок).

4) В деплое заменить cp -al на «копировать только нужное»
Если деплой сейчас делает новый релиз через cp -al, подумайте о модели:
- хранить релиз как распакованный артефакт (обычные файлы);
- использовать
rsyncбез--link-destна релизной папке; - выкатывать образ/контейнер (если это подходит проекту и инфраструктуре).
Смысл один: перестать увеличивать inode link count на одних и тех же файлах при каждом релизе.
5) Проверить, не создаёте ли вы hard links «случайно»
Иногда EMLINK появляется не из-за осознанного cp -al, а из-за того, что в пайплайн добавили сохранение/восстановление hard links:
rsync -H(сохранять hard links при копировании);- распаковка tar-архива, содержащего hard links;
- инструменты дедупликации, которые «экономят место», заменяя одинаковые файлы hard link’ами.
Если hard links не часть вашей архитектуры — проще их отключить, чем лечить последствия.
Мини-рунбук: типичный CI deploy error и что делать прямо сейчас
Если деплой уже падает, действуйте так:
Найдите конкретный файл, на котором упало (из лога CI).
Проверьте число ссылок:
stat -c 'links=%h inode=%i %n' /path/to/fileЕсли
linksочень большое — оцените масштаб размножения inode:inode=$(stat -c '%i' /path/to/file); find /path/to/releases -xdev -inum "$inode" | wc -lСрочно сократите число релизов/снимков (удалите старые) либо переключите деплой на обычное копирование для этого прогона.
После восстановления сервиса — исправьте процесс: ротация релизов, пересборка артефактов, исключение зависимостей из hardlink-схемы.
Почему «просто увеличить лимит» нельзя
Вопрос «как увеличить hardlink limit» возникает всегда. В Linux это не sysctl и не лимит процесса — это ограничение формата/реализации файловой системы и поведения совместимых инструментов. Для ext4 это особенно жёстко: упёрлись — значит, архитектурно надо менять подход (ротация, отказ от hard links на горячем пути, другая модель деплоя/бэкапа).
Чеклист профилактики
Держите конечное число релизов и бэкап-снимков. «Храним всё» почти всегда заканчивается EMLINK или переполнением диска.
Не линковать hard link’ами каталоги зависимостей и сборочные output’ы, если релизов много.
Явно документируйте, где в инфраструктуре допускаются hard links: деплой, бэкап, дедупликация.
Периодически сканируйте на аномально большой
inode link countв релизных/бэкапных деревьях.
Итог
Too many links/EMLINK — ожидаемый результат, когда схема деплоя или бэкапа слишком активно переиспользует один inode через hard links. На ext4 вы чаще упрётесь в предел около 65k, на XFS проблема может проявляться иначе, но суть та же: бесконтрольное размножение ссылок — это техдолг.
Самые надёжные решения: ротация релизов/снимков, отказ от hardlink-деревьев для зависимостей, и пересборка пайплайна так, чтобы он создавал артефакт и раскатывал его без «умной» дедупликации на файловой системе.
Если вы переносите проекты на отдельный сервер под CI/деплой или бэкапы, удобно держать это на VDS, чтобы гибко управлять дисками, ФС и политиками хранения.


