Симптомы

  • Часть 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).

Пошагово были исключены следующие гипотезы:

  1. DNS-резолвингgetent hosts / dig показывали корректный, актуальный адрес. Не причина.
  2. ARP-кэшip neigh flush all не помог. Не причина.
  3. Kernel keyring (dns_resolver / cifs.upcall) — keyctl clear @s / @u не помог. Не причина.
  4. /proc/fs/cifs/dfscache — сброс не помог. Не причина.
  5. /etc/samba/lmhosts — файл пуст. Не причина.
  6. /proc/fs/cifs/DebugData — показывал Servers: [NONE], то есть резидентных сессий в ядре нет, резолвинг идёт заново при каждой попытке — и всё равно упирается в старый адрес.
  7. 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. После него клиент:

  1. Отправляет TRANS2 GET_DFS_REFERRAL запрос к DC.
  2. Получает от DC ответ с реальным IP файлового сервера-таргета.
  3. Разрывает сессию с DC (Tree Disconnect) и пытается подключиться к таргету.
  4. Таргет оказывается старым, уже неактуальным IP-адресом ноды — до переноса эта нода была там, сейчас у неё другой адрес.
  5. Соединение виснет 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 cifsmodprobe -r cifs. rmmod выгружает только указанный модуль. modprobe -r выгружает модуль и все его неиспользуемые зависимости (аналог apt autoremove для модулей ядра) — именно в зависимости, судя по всему, и залипало состояние DFS/DNS-резолвинга.

Что нужно поправить на стороне DFS/AD

При следующем переносе DFS-нод в другой сегмент сети сообщать администраторам AD/DFS заранее:

  1. Проверить/обновить target в DFS Folder до переноса:
    Get-DfsnFolderTarget -Path "\\corp.example.internal\Workgroups\<Share>"
    Set-DfsnFolderTarget ...
    
  2. После обновления конфигурации — принудительно сбросить referral-кэш на всех DC, обслуживающих namespace:
    dfsutil /pktflush
    
  3. Проверить репликацию 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'