Поиск по сайту:

Мысли о мониторинге изменений файлов в Linux по сети


На этой странице

  1. Почему это?
  2. Возможный сценарий:
  3. Примечания.

Мониторинг каталога на наличие изменений в Linux возможен с помощью известного механизма inotify. С помощью inotify можно установить наблюдение за каталогом, настроить его для наблюдения за событиями в содержимом, и вы будете получать сообщения о файловом дескрипторе, когда что-то происходит. Это отлично работает, когда каталог находится в локальном хранилище, например на жестком диске, SSD или USB-накопителе, но этого недостаточно, когда каталог находится в сетевой файловой системе, когда хранилище находится на другом компьютере. Другой пользователь, работающий в том же каталоге, подключенный через ту же или другую файловую систему, может удалить файл, и установленные вами часы не получат уведомления.

Почему это?

По задумке, inotify получает результат операции (например, mkdir или chmod), но неизвестно, в какой файловой системе находятся часы (черный ящик) для inotify. Файловая система не «знает», что часы были установлены, и поэтому не может предпринять правильные действия, такие как уведомление удаленного хоста, на котором кто-то хочет наблюдать за каталогом.

Пока вы единственный пользователь, проблем нет. Это становится проблемой, когда в каталоге, за которым вы хотите наблюдать, работает больше пользователей.

Вы можете сравнить это поведение с публичной библиотекой. Когда вы являетесь единственным пользователем, вы можете знать, какие книги доступны, а какие нет, так как вы знаете, какие из них вы взяли напрокат. Это больше невозможно, когда вы не единственный пользователь, есть больше пользователей, одалживающих книги.

В этом случае кто-то в библиотеке должен управлять тем, что берет любой пользователь (что является обычным случаем), и вы должны связаться с этим человеком, чтобы узнать, доступна ли книга или нет. Это все равно, что попросить кого-нибудь сообщить вам, когда книга, которой сейчас нет, снова будет доступна.

Теперь этот контакт с библиотекой, чтобы сообщить вам, не работает с Linux, где, конечно, библиотека - это удаленное хранилище, а сервер - это «кто-то», кто работает в библиотеке.

Чтобы заставить это работать с Linux, нужно заставить удаленный сервер получать уведомления о том, что часы были установлены.

На самом деле, файловые системы, такие как CIFS и последние версии NFS, содержат поддержку отправки часов на сервер: для CIFS в строке 6438 файла fs/cifs/cifssmb.c ядра 4.1.2 сообщение SMB для этого (NT_TRANSACT_NOTIFY_CHANGE) закомментировано. но все же присутствует. Причина комментирования этого заключается в том, что он работал с dnotify, который уже давно не является системой fsnotify по умолчанию для Linux.


Заставить переадресацию часов работать в Linux с сетевыми файловыми системами и FUSE можно через пространство ядра.

Недавно Ive попытался реализовать эту «переадресацию часов на сервер» с помощью FUSE. Пришлось патчить:

Модуль ядра FUSE для принятия мер после получения уведомления от fsnotify. Я представил новый код операции
FUSE_FSNOTIFY, который модуль ядра отправляет демону пользовательского пространства вместе с номером inodenumber и маской.

Библиотека FUSE для приема и обработки событий fs и отправки отчетов о них в VFS.

При более внимательном рассмотрении того, как все работает, когда файловая система пользовательского пространства успешно установила часы на своем бэкэнде (обратите внимание, что он также может ответить ENOSYS), бэкэнд может отправить событие на часы в любой момент, до тех пор, пока часы сняты. Что делать с этим событием?

Возможный сценарий:

Введите дополнительный код операции FUSE FUSE_FSNOTIFY_EVENT, преобразуйте маску в событии, полученном от внутреннего протокола, во что-то, понятное fsnotify, и отправьте его обратно в модуль FUSE, используя новый код операции, индексный дескриптор часов, имя записи и переведенная маска. Модуль FUSE в свою очередь отправляет его в подсистему fsnotify, которая информирует листнеры (inotify и/или fanotify), где предоставляется информация о том, что событие находится на бэкенде. (требуется дополнительный флаг события, например для inotify маска события IN_REMOTE, для fanotify FAN_REMOTE). Что делать с этой информацией, зависит от слушателя. Локальная VFS может быть уже обновлена, а может и не быть.

Ноты:

Преобразование маски из бэкенда во что-то, что понимает fsnotify, может быть очень простым и не очень простым, в зависимости от события. Основные события, такие как создание (или удаление) записи в отслеживаемом каталоге, просты (FS_CREATE и FS_DELETE соответственно), смена владельца также не так сложна (FS_ATTRIB), но что-то вроде расширенного атрибута (SMB использует их много) можно преобразовать только во что-то общее как FS_ATTRIB.

Модуль FUSE должен проверить, действительно ли часы и/или индексный дескриптор, а также применима ли маска часов к маске событий.

Требуются дополнительные биты маски IN_REMOTE (для inotify) и FAN_REMOTE (для fanotify).

Двойной информации следует избегать. Это сложно. Например, создание файла в отслеживаемом каталоге на том же хосте, на котором стоит вахта. Если эта операция выполнена успешно, это вызовет событие fsnotify FS_CREATE, а также создаст FS_CREATE | FS_REMOTE, так как операция выполнена успешно на серверной части, что приводит к этому сообщению (из серверной части → библиотека Fuse → модуль ядра FUSE → подсистема fsnotify → inotify и/или fanotify).

Один из способов решить эту проблему — попросить бэкэнд отправлять только события, инициированные другими. Для серверной части довольно просто сравнить инициатора (хоста) события FS с хостом, выполняющим соединение.

Другое решение — сравнить сообщаемое событие с локальным кешем в библиотеке fuse и модуле FUSE. В примере с созданием файла библиотека (и модуль FUSE) должны проверить, существует ли запись в отслеживаемом каталоге. Если нет, то это не инициировано этим хостом. Для удаления это аналогично.

Для других событий, таких как запись в файл или изменение владельца, этого метода недостаточно, дополнительная информация о том, что изменилось удаленно (например, новый размер, новый владелец), должна быть в сообщении, отправленном удаленным хостом.

Если эта информация не предоставляется бэкендом, другое решение состоит в том, чтобы демон, ответственный за наблюдение за событиями FS от имени клиентов, поддерживал кэш последних локальных событий. Если сообщается об удаленном событии, а в кеше не найден локальный эквивалент, оно инициируется другим хостом. Это может стать сложной задачей, поскольку о событиях сообщается с использованием соединения для определенного пользователя, другие пользователи могут быть авторизованы или не авторизованы для получения событий. И насколько большим будет этот кеш?

Я использовал FUSE выше, я думаю, что он аналогичен для других файловых систем, таких как CIFS и NFS.

Ах да, есть еще один вариант: просто опрашивать каждые 5 секунд или около того.

Стеф Бон