Có thể theo dõi thư mục để biết các thay đổi với Linux thông qua cơ chế inotify nổi tiếng. Với inotify, bạn có thể thiết lập chế độ theo dõi trên thư mục, cấu hình để theo dõi các sự kiện trên nội dung và bạn sẽ nhận được thông báo trên một mô tả tệp khi có điều gì đó xảy ra. Điều này hoạt động hoàn hảo khi thư mục nằm trên bộ lưu trữ cục bộ, như ổ cứng, SSD hoặc ổ USB, nhưng không đủ khi thư mục nằm trên hệ thống tệp mạng khi bộ lưu trữ nằm trên máy tính khác. Một người dùng khác làm việc trong cùng thư mục, được kết nối qua cùng một hệ thống tệp hoặc một hệ thống tệp khác, có thể xóa một tệp và chế độ theo dõi mà bạn đã thiết lập trên tệp đó sẽ không nhận được thông báo.
Miễn là bạn là người dùng duy nhất, thì không có vấn đề gì. Vấn đề sẽ trở thành vấn đề khi có nhiều người dùng hơn làm việc trong thư mục mà bạn muốn theo dõi.
Bạn có thể so sánh hành vi này với thư viện công cộng. Khi bạn là người dùng duy nhất, bạn có thể biết sách nào có sẵn và sách nào không có sẵn vì bạn biết sách nào bạn đã mượn. Điều này không thể thực hiện được nữa khi bạn không phải là người dùng duy nhất, có nhiều người dùng hơn đang mượn sách.
Trong trường hợp đó, ai đó trong thư viện sẽ quản lý những gì người dùng nào đó mượn (đây là trường hợp thông thường) và bạn phải liên hệ với người này để biết sách có sẵn hay không. Giống như yêu cầu ai đó thông báo cho bạn khi một cuốn sách hiện không có, có sẵn trở lại.
Bây giờ, việc liên hệ với thư viện để thông báo cho bạn không hoạt động với Linux, trong đó tất nhiên thư viện là bộ lưu trữ từ xa và máy chủ là "ai đó" đang làm việc trong thư viện.
Để làm cho việc này hoạt động với Linux là để máy chủ từ xa nhận được thông báo rằng một chế độ theo dõi đã được thiết lập.
Trên thực tế, các hệ thống tệp như CIFS và các phiên bản NFS gần đây có hỗ trợ gửi chế độ theo dõi đến máy chủ: đối với CIFS ở dòng 6438 của fs/cifs/cifssmb.c của kernel 4.1.2, thông báo SMB cho mục này (NT_TRANSACT_NOTIFY_CHANGE) đã được chú thích nhưng vẫn có. Lý do để bình luận điều này là vì nó hoạt động với dnotify, vốn không phải là hệ thống fsnotify mặc định cho Linux trong một thời gian dài.
Có thể thực hiện chuyển tiếp watch hoạt động trên Linux với hệ thống tệp mạng và FUSE thông qua không gian kernel.
Gần đây tôi đã thử triển khai "chuyển tiếp watch đến máy chủ" này bằng FUSE. Tôi đã phải vá:
Hệ thống con kernel fsnotify, để thông báo cho mô-đun kernel FUSE rằng watch đã được đặt hoặc xóa trên một inode.
Mô-đun kernel FUSE thực hiện hành động sau khi được fsnotify thông báo. Tôi đã giới thiệu một mã hoạt động mới
FUSE_FSNOTIFY mà mô-đun hạt nhân gửi đến daemon không gian người dùng cùng với inodenumber và mask.
Thư viện FUSE để nhận và xử lý lệnh gọi FUSE_FSNOTIFY bằng cách gọi đúng hàm của hệ thống tệp không gian người dùng.
Thư viện FUSE để nhận và xử lý các sự kiện fs và báo cáo lại những sự kiện đó cho VFS.
Xem xét kỹ hơn cách mọi thứ hoạt động, khi đồng hồ đã được hệ thống tệp không gian người dùng thiết lập thành công trên phần phụ trợ của nó (lưu ý rằng nó cũng có thể trả lời ENOSYS), phần phụ trợ có thể gửi sự kiện trên đồng hồ bất kỳ lúc nào, cho đến khi đồng hồ bị xóa. Phải làm gì với sự kiện này?
Mô-đun FUSE phải kiểm tra xem watch và/hoặc inode có còn hợp lệ không và liệu mặt nạ của watch có áp dụng cho eventmask không.
Cần có các bit mặt nạ bổ sung IN_REMOTE (đối với inotify) và FAN_REMOTE (đối với fanotify).
Cần tránh thông tin trùng lặp. Điều này rất khó khăn. Ví dụ: tạo tệp trong thư mục được theo dõi trên cùng máy chủ với watch đang bật. Khi thao tác này thành công, nó sẽ gây ra sự kiện fsnotify FS_CREATE và nó cũng sẽ tạo sự kiện FS_CREATE | FS_REMOTE vì thao tác được thực hiện thành công ở phần phụ trợ, dẫn đến thông báo này (từ phần phụ trợ→thư viện fuse→mô-đun hạt nhân FUSE→hệ thống con fsnotify→inotify và/hoặc fanotify).
Một cách để giải quyết vấn đề này là yêu cầu phần phụ trợ chỉ gửi các sự kiện do người khác khởi tạo. Đối với phần phụ trợ, khá đơn giản để so sánh trình khởi tạo (máy chủ) của sự kiện FS với máy chủ tạo kết nối.
Một giải pháp khác là so sánh sự kiện được báo cáo với bộ đệm cục bộ trong thư viện fuse và mô-đun FUSE. Với ví dụ tạo tệp, thư viện (và mô-đun FUSE) sẽ kiểm tra mục đã tồn tại trong thư mục được theo dõi chưa. Nếu chưa, mục đó không được máy chủ này khởi tạo. Đối với lệnh xóa, điều này cũng tương tự.
Đối với các sự kiện khác, như ghi vào tệp hoặc thay đổi chủ sở hữu, phương pháp này không đủ, thông tin bổ sung về những gì đã thay đổi từ xa (như kích thước mới, chủ sở hữu mới) phải có trong thông báo do máy chủ từ xa gửi.
Nếu thông tin đó không được cung cấp bởi phần phụ trợ, một giải pháp khác là để daemon chịu trách nhiệm theo dõi các sự kiện FS thay mặt cho máy khách duy trì bộ đệm các sự kiện cục bộ gần đây. Nếu một sự kiện từ xa được báo cáo và trong bộ đệm không tìm thấy sự kiện cục bộ tương đương, sự kiện đó sẽ được khởi tạo bởi máy chủ khác. Điều này có thể trở nên khó khăn vì các sự kiện được báo cáo bằng kết nối cho một người dùng nhất định, những người dùng khác có thể được hoặc không được phép nhận sự kiện. Và bộ đệm này sẽ lớn đến mức nào?
Tôi đã sử dụng FUSE ở trên, tôi nghĩ nó tương tự đối với các hệ thống tệp khác như CIFS và NFS.
Ồ và vâng, vẫn còn một tùy chọn khác: chỉ cần thăm dò sau mỗi 5 giây hoặc lâu hơn.
Stef Bon
Tại sao lại như vậy?
Theo thiết kế, inotify nhận được kết quả của một thao tác (như mkdir hoặc chmod) nhưng không biết chế độ theo dõi đó nằm trên loại hệ thống tệp nào (một hộp đen) đối với inotify. Hệ thống tệp không "biết" một chế độ theo dõi đã được thiết lập và do đó không thể thực hiện hành động đúng, chẳng hạn như thông báo cho máy chủ từ xa rằng có người muốn theo dõi một thư mục.Miễn là bạn là người dùng duy nhất, thì không có vấn đề gì. Vấn đề sẽ trở thành vấn đề khi có nhiều người dùng hơn làm việc trong thư mục mà bạn muốn theo dõi.
Bạn có thể so sánh hành vi này với thư viện công cộng. Khi bạn là người dùng duy nhất, bạn có thể biết sách nào có sẵn và sách nào không có sẵn vì bạn biết sách nào bạn đã mượn. Điều này không thể thực hiện được nữa khi bạn không phải là người dùng duy nhất, có nhiều người dùng hơn đang mượn sách.
Trong trường hợp đó, ai đó trong thư viện sẽ quản lý những gì người dùng nào đó mượn (đây là trường hợp thông thường) và bạn phải liên hệ với người này để biết sách có sẵn hay không. Giống như yêu cầu ai đó thông báo cho bạn khi một cuốn sách hiện không có, có sẵn trở lại.
Bây giờ, việc liên hệ với thư viện để thông báo cho bạn không hoạt động với Linux, trong đó tất nhiên thư viện là bộ lưu trữ từ xa và máy chủ là "ai đó" đang làm việc trong thư viện.
Để làm cho việc này hoạt động với Linux là để máy chủ từ xa nhận được thông báo rằng một chế độ theo dõi đã được thiết lập.
Trên thực tế, các hệ thống tệp như CIFS và các phiên bản NFS gần đây có hỗ trợ gửi chế độ theo dõi đến máy chủ: đối với CIFS ở dòng 6438 của fs/cifs/cifssmb.c của kernel 4.1.2, thông báo SMB cho mục này (NT_TRANSACT_NOTIFY_CHANGE) đã được chú thích nhưng vẫn có. Lý do để bình luận điều này là vì nó hoạt động với dnotify, vốn không phải là hệ thống fsnotify mặc định cho Linux trong một thời gian dài.
Có thể thực hiện chuyển tiếp watch hoạt động trên Linux với hệ thống tệp mạng và FUSE thông qua không gian kernel.
Gần đây tôi đã thử triển khai "chuyển tiếp watch đến máy chủ" này bằng FUSE. Tôi đã phải vá:
Hệ thống con kernel fsnotify, để thông báo cho mô-đun kernel FUSE rằng watch đã được đặt hoặc xóa trên một inode.
Mô-đun kernel FUSE thực hiện hành động sau khi được fsnotify thông báo. Tôi đã giới thiệu một mã hoạt động mới
FUSE_FSNOTIFY mà mô-đun hạt nhân gửi đến daemon không gian người dùng cùng với inodenumber và mask.
Thư viện FUSE để nhận và xử lý lệnh gọi FUSE_FSNOTIFY bằng cách gọi đúng hàm của hệ thống tệp không gian người dùng.
Thư viện FUSE để nhận và xử lý các sự kiện fs và báo cáo lại những sự kiện đó cho VFS.
Xem xét kỹ hơn cách mọi thứ hoạt động, khi đồng hồ đã được hệ thống tệp không gian người dùng thiết lập thành công trên phần phụ trợ của nó (lưu ý rằng nó cũng có thể trả lời ENOSYS), phần phụ trợ có thể gửi sự kiện trên đồng hồ bất kỳ lúc nào, cho đến khi đồng hồ bị xóa. Phải làm gì với sự kiện này?
Một kịch bản có thể xảy ra:
Giới thiệu một opcode FUSE bổ sung FUSE_FSNOTIFY_EVENT, dịch mặt nạ trong sự kiện nhận được từ giao thức phụ trợ thành thứ gì đó mà fsnotify hiểu được và gửi lại cho mô-đun FUSE bằng opcode mới, inode của watch, tên của mục nhập và mặt nạ đã dịch. Đến lượt mình, mô-đun FUSE sẽ gửi nó đến hệ thống con fsnotify, hệ thống này sẽ thông báo cho những người nghe (inotify và hoặc fanotify), nơi cung cấp thông tin rằng sự kiện nằm ở phía sau. (cần có cờ sự kiện bổ sung, ví dụ đối với inotify mặt nạ sự kiện IN_REMOTE, đối với fanotify FAN_REMOTE). Người nghe quyết định phải làm gì với thông tin này. VFS địa phương có thể đã được cập nhật hoặc chưa.Ghi chú:
Việc biên dịch mặt nạ từ phần phụ trợ thành thứ mà fsnotify hiểu có thể rất dễ hoặc không dễ, tùy thuộc vào sự kiện. Các sự kiện cơ bản như tạo (hoặc xóa) mục trong thư mục được theo dõi rất đơn giản (tương ứng với FS_CREATE và FS_DELETE), việc thay đổi chủ sở hữu cũng không quá khó (FS_ATTRIB), nhưng một thứ gì đó như thuộc tính mở rộng (SMB sử dụng rất nhiều thuộc tính đó) chỉ có thể được biên dịch thành thứ gì đó chung chung như FS_ATTRIB.Mô-đun FUSE phải kiểm tra xem watch và/hoặc inode có còn hợp lệ không và liệu mặt nạ của watch có áp dụng cho eventmask không.
Cần có các bit mặt nạ bổ sung IN_REMOTE (đối với inotify) và FAN_REMOTE (đối với fanotify).
Cần tránh thông tin trùng lặp. Điều này rất khó khăn. Ví dụ: tạo tệp trong thư mục được theo dõi trên cùng máy chủ với watch đang bật. Khi thao tác này thành công, nó sẽ gây ra sự kiện fsnotify FS_CREATE và nó cũng sẽ tạo sự kiện FS_CREATE | FS_REMOTE vì thao tác được thực hiện thành công ở phần phụ trợ, dẫn đến thông báo này (từ phần phụ trợ→thư viện fuse→mô-đun hạt nhân FUSE→hệ thống con fsnotify→inotify và/hoặc fanotify).
Một cách để giải quyết vấn đề này là yêu cầu phần phụ trợ chỉ gửi các sự kiện do người khác khởi tạo. Đối với phần phụ trợ, khá đơn giản để so sánh trình khởi tạo (máy chủ) của sự kiện FS với máy chủ tạo kết nối.
Một giải pháp khác là so sánh sự kiện được báo cáo với bộ đệm cục bộ trong thư viện fuse và mô-đun FUSE. Với ví dụ tạo tệp, thư viện (và mô-đun FUSE) sẽ kiểm tra mục đã tồn tại trong thư mục được theo dõi chưa. Nếu chưa, mục đó không được máy chủ này khởi tạo. Đối với lệnh xóa, điều này cũng tương tự.
Đối với các sự kiện khác, như ghi vào tệp hoặc thay đổi chủ sở hữu, phương pháp này không đủ, thông tin bổ sung về những gì đã thay đổi từ xa (như kích thước mới, chủ sở hữu mới) phải có trong thông báo do máy chủ từ xa gửi.
Nếu thông tin đó không được cung cấp bởi phần phụ trợ, một giải pháp khác là để daemon chịu trách nhiệm theo dõi các sự kiện FS thay mặt cho máy khách duy trì bộ đệm các sự kiện cục bộ gần đây. Nếu một sự kiện từ xa được báo cáo và trong bộ đệm không tìm thấy sự kiện cục bộ tương đương, sự kiện đó sẽ được khởi tạo bởi máy chủ khác. Điều này có thể trở nên khó khăn vì các sự kiện được báo cáo bằng kết nối cho một người dùng nhất định, những người dùng khác có thể được hoặc không được phép nhận sự kiện. Và bộ đệm này sẽ lớn đến mức nào?
Tôi đã sử dụng FUSE ở trên, tôi nghĩ nó tương tự đối với các hệ thống tệp khác như CIFS và NFS.
Ồ và vâng, vẫn còn một tùy chọn khác: chỉ cần thăm dò sau mỗi 5 giây hoặc lâu hơn.
Stef Bon