Симптомы
- Часть DFS-шар на Linux-хостах (монтирование через
autofs+mount.cifs) перестала монтироваться после переноса части нод файлового кластера в другой сегмент сети. - Ошибка в
dmesg:CIFS: VFS: Error connecting to socket. Aborting operation. CIFS: VFS: cifs_mount failed w/return code = -115 - Падают не все шары, а только определённые — те, чьи данные физически лежат на перенесённых нодах.
- Параметры монтирования (
vers=,uid=,gid=,credentials=и т.д.) у рабочих и нерабочих шар идентичны. smbclient -Lи ручное подключение к серверу проходит нормально.- Полная перезагрузка Linux-хоста временно решает проблему для конкретного сервера, но не является решением — на другом идентичном хосте без перезагрузки проблема сохраняется сколь угодно долго.
Ход диагностики
Код -115 = таймаут на уровне сокета при попытке установить TCP-соединение. Это не ошибка авторизации (в отличие от -13 = EACCES).
Пошагово были исключены следующие гипотезы:
- DNS-резолвинг —
getent hosts/digпоказывали корректный, актуальный адрес. Не причина. - ARP-кэш —
ip neigh flush allне помог. Не причина. - Kernel keyring (
dns_resolver/cifs.upcall) —keyctl clear @s/@uне помог. Не причина. /proc/fs/cifs/dfscache— сброс не помог. Не причина./etc/samba/lmhosts— файл пуст. Не причина./proc/fs/cifs/DebugData— показывалServers: [NONE], то есть резидентных сессий в ядре нет, резолвинг идёт заново при каждой попытке — и всё равно упирается в старый адрес.umount -a -t cifs+rmmod cifs+modprobe cifs— не помогло (см. ключевую находку ниже).
Как нашли реальную причину
strace -f -tt на mount.cifs показал прямой вызов ядра:
mount("//corp.example.internal/Workgroups/Operations", ".", "cifs", MS_NOSUID,
"ip=10.76.128.24,unc=\\\\corp...")
= -1 EINPROGRESS (10.427507 сек, затем -115)
mount.cifs резолвит DFS-namespace в адрес контроллера домена — и это соединение к DC проходит нормально (порт 445 открыт, smbclient подключается без проблем).
Включение подробного debug-лога CIFS-модуля в ядре:
echo 7 > /proc/fs/cifs/cifsFYI
echo 1 > /proc/fs/cifs/traceSMB
dmesg -T | tail -100
показало суть:
CIFS: Status code returned 0xc0000257 STATUS_PATH_NOT_COVERED
Это стандартный SMB-статус: путь находится в DFS-пространстве, обратитесь за referral. После него клиент:
- Отправляет
TRANS2 GET_DFS_REFERRALзапрос к DC. - Получает от DC ответ с реальным IP файлового сервера-таргета.
- Разрывает сессию с DC (
Tree Disconnect) и пытается подключиться к таргету. - Таргет оказывается старым, уже неактуальным IP-адресом ноды — до переноса эта нода была там, сейчас у неё другой адрес.
- Соединение виснет 10 секунд (таймаут) →
-115.
Подтверждено через tcpdump + tshark:
tshark -r dump.pcap -Y "ip.addr==<DC_IP> || ip.addr==<target_ip>" \
-T fields -e frame.number -e ip.src -e ip.dst -e smb2.cmd
Видна последовательность: IOCTL (cmd=11, DFS referral request) → Tree Disconnect → появление старого адреса таргета в трафике.
Корневая причина
DFS-referral, который отдают некоторые контроллеры домена, обслуживающие namespace, продолжал указывать на старый (уже неактуальный) IP ноды после её физического переноса. Это не проблема клиента, DNS, ARP или любого клиентского кэша — DC сам возвращает устаревший адрес в ответ на FSCTL_DFS_GET_REFERRAL.
Возможные причины на стороне DFS/AD:
- Target в DFS Folder (
Get-DfsnFolderTarget) не обновили при переносе ноды. - Referral-кэш конкретных DC (у каждого DC свой независимый кэш с TTL, обычно
TargetListCacheLifetime~30 мин) ещё не сброшен (dfsutil /pktflushвыполняется на самом DC, а не на клиенте). - DC несколько, и клиент “прилипает” к одному из них (DC locator/affinity) — разные хосты и попытки монтирования могли получать referral от разных DC: часть уже с актуальными данными, часть ещё нет. Этим объясняется, почему на одном хосте помогла перезагрузка (клиент заново выбрал DC и попал на “свежий”), а на другом — нет.
Почему не помогали стандартные шаги на клиенте
| Действие | Результат | Почему |
|---|---|---|
rmmod cifs + modprobe cifs | не помогло | rmmod выгружает только сам модуль, не трогая зависимости (например dns_resolver), в которых, вероятно, и сидело резидентное состояние |
modprobe -r cifs + modprobe cifs | помогло | modprobe -r выгружает модуль вместе со всеми неиспользуемыми зависимостями — полностью сбрасывает состояние, аналогично тому, что происходит при reboot |
| Полная перезагрузка хоста | помогало, но нестабильно | Сбрасывает всё состояние клиента, включая выбор DC — при повторном резолвинге клиент может попасть на другой (уже обновившийся) DC. По сути — “повезло с выбором”, а не системное решение |
Итоговое решение
sudo modprobe -r cifs # НЕ rmmod!
sudo modprobe cifs
Без необходимости перезагружать весь сервер.
rmmod cifs ≠ modprobe -r cifs.
rmmod выгружает только указанный модуль.
modprobe -r выгружает модуль и все его неиспользуемые зависимости (аналог apt autoremove для модулей ядра) — именно в зависимости, судя по всему, и залипало состояние DFS/DNS-резолвинга.Что нужно поправить на стороне DFS/AD
При следующем переносе DFS-нод в другой сегмент сети сообщать администраторам AD/DFS заранее:
- Проверить/обновить target в DFS Folder до переноса:
Get-DfsnFolderTarget -Path "\\corp.example.internal\Workgroups\<Share>" Set-DfsnFolderTarget ... - После обновления конфигурации — принудительно сбросить referral-кэш на всех DC, обслуживающих namespace:
dfsutil /pktflush - Проверить репликацию DFS-конфигурации между контроллерами домена (
repadmin /replsummary), чтобы исключить рассинхрон между DC.
Шпаргалка команд
# Посмотреть активные CIFS-сессии в ядре
cat /proc/fs/cifs/DebugData
# Включить подробный debug CIFS-модуля
echo 7 > /proc/fs/cifs/cifsFYI
echo 1 > /proc/fs/cifs/traceSMB
dmesg -T | tail -100
echo 0 > /proc/fs/cifs/cifsFYI
# Сбросить DFS-кэш ядра
echo 0 | sudo tee /proc/fs/cifs/dfscache
# Правильная выгрузка модуля со всеми зависимостями
sudo modprobe -r cifs
sudo modprobe cifs
# strace на попытку монтирования
strace -f -tt -o /tmp/trace.log mount -t cifs //server/share /mnt/test -o credentials=...
grep -E "connect|mount\(" /tmp/trace.log
# Захват трафика + разбор SMB2 команд
sudo tcpdump -i <iface> -n port 445 -w /tmp/dump.pcap
tshark -r /tmp/dump.pcap -Y "smb2" -T fields -e frame.number -e ip.src -e ip.dst -e smb2.cmd
# cmd 11 = IOCTL (в т.ч. DFS referral request), cmd 4 = Tree Disconnect
# Проверить SMB-доступность конкретного сервера напрямую (в обход DFS)
smbclient -L //<ip> -U 'DOMAIN\user'
smbclient //<ip>/<share> -U 'DOMAIN\user' -c 'ls'