日本a√视频在线,久久青青亚洲国产,亚洲一区欧美二区,免费g片在线观看网站

        <style id="k3y6c"><u id="k3y6c"></u></style>
        <s id="k3y6c"></s>
        <mark id="k3y6c"></mark>
          
          

          <mark id="k3y6c"></mark>

          "); //-->

          博客專欄

          EEPW首頁 > 博客 > 監(jiān)聽容器中的文件系統(tǒng)事件

          監(jiān)聽容器中的文件系統(tǒng)事件

          發(fā)布人:電子禪石 時間:2024-09-18 來源:工程師 發(fā)布文章
          基本概念

          Linux 文件系統(tǒng)事件監(jiān)聽:應(yīng)用層的進程操作目錄或文件時,會觸發(fā) system call,此時,內(nèi)核中的 notification 子系統(tǒng)把該進程對文件的操作事件上報給應(yīng)用層的監(jiān)聽進程(稱為 listerner)。

          dnotify:2001 年的 kernel 2.4 版本引入,只能監(jiān)控 directory,采用的是 signal 機制來向 listener 發(fā)送通知,可以傳遞的信息很有限。

          inotify:2005 年在 kernel 2.6.13 中亮相,除了可以監(jiān)控目錄,還可以監(jiān)聽普通文件,inotify 擯棄了 signal 機制,通過 event queue 向 listener 上傳事件信息。

          fanotify:kernel 2.6.36 引入,fanotify 的出現(xiàn)解決了已有實現(xiàn)只能 notify 的問題,允許 listener 介入并改變文件事件的行為,實現(xiàn)從“監(jiān)聽”到“監(jiān)控”的跨越。

          本文主要介紹如何通過 inotify 和 fanotify 監(jiān)聽容器中的文件系統(tǒng)事件。

          Inotify基本介紹

          inotify(inode[1] notify)是 Linux 內(nèi)核中的一個子系統(tǒng),由 John McCutchan[2] 創(chuàng)建,用于監(jiān)視文件系統(tǒng)事件。它可以在文件或目錄發(fā)生變化時通知應(yīng)用程序,例如,監(jiān)聽文件的創(chuàng)建、修改或刪除事件。inotify 可以用于自動更新文件系統(tǒng)視圖、重新加載配置文件,記錄文件改變歷史等場景。

          Inotify 的工作流程如下:

          1. 用戶通過系統(tǒng)調(diào)用(如:write、read)操作文件;

          2. 內(nèi)核將文件系統(tǒng)事件保存到 fsnotify_group 的事件隊列中;

          3. 喚醒等待 inotify 的進程(listener);

          4. 進程通過 fd 從內(nèi)核隊列讀取 inotify 事件。

          圖片

          其中,inotify_event_info 的定義如下:

          c

          mask 標記具體的文件操作事件。

          API 介紹

          Inotify 可以用來監(jiān)聽單個文件,也可以用來監(jiān)聽目錄。當(dāng)監(jiān)聽的是目錄時,inotify 除了生成目錄的事件,還會生成目錄中文件的事件。

          注意:當(dāng)使用 inotify 監(jiān)聽目錄時,并不會遞歸監(jiān)聽子目錄中的文件,如果需要得到這些事件,需要手動指定監(jiān)聽這些文件。對于很大的目錄樹,這個過程將花費大量時間。

          參考:inotify.7[3]

          • inotify_init(void)

          初始化 inotify 實例,返回文件描述符,用于內(nèi)核向用戶態(tài)程序傳輸監(jiān)聽到的 inotify 事件。函數(shù)聲明為:

          c

          內(nèi)核同時提供了int inotify_init1(int flags),flags 的可選值如下:

          c

          可以通過 OR 指定多個flag,當(dāng)flags=0等價于int inotify_init(void)。

          • inotify_add_watch

          添加需要監(jiān)聽的目錄或文件(watch list),可以添加新的路徑,也可以是已經(jīng)添加過的路徑。fd 是inotify_init返回的文件描述符,mask 指定需要監(jiān)聽的事件類型,通過 OR 指定多個事件。返回值是當(dāng)前路徑的wd(watch descriptor),可用于移除對該路徑的監(jiān)聽。

          函數(shù)聲明為:

          c

          Inotify 支持監(jiān)聽的事件包括:

          c
          • inotify_rm_watch

          移除被監(jiān)聽的路徑。fd 是inotify_init返回的文件描述符,wd 是inotify_add_watch返回的監(jiān)聽文件描述符。

          函數(shù)聲明為:

          c
          實例

          以下是基于 Rust 語言實現(xiàn)的實例:

          rust
          use nix::{    poll::{poll, PollFd, PollFlags},    sys::inotify::{AddWatchFlags, InitFlags, Inotify, InotifyEvent},};use signal_hook::{consts::SIGTERM, low_level::pipe};use std::os::unix::net::UnixStream;use std::{env, io, os::fd::AsRawFd, path::PathBuf};fn main() -> io::Result<()> {    let args: Vec<String> = env::args().collect();    if args.len() < 2 {        eprintln!("Usage: {} <path>", args[0]);        std::process::exit(1);    }    let path = PathBuf::from(&args[1]);    // 初始化 inotify,得到 fd    let inotify_fd = Inotify::init(InitFlags::empty())?;    // 添加被監(jiān)聽的目錄或文件,指定需要監(jiān)聽的事件    let wd = inotify_fd.add_watch(        &path,        AddWatchFlags::IN_ACCESS | AddWatchFlags::IN_OPEN | AddWatchFlags::IN_CREATE,    )?;    let (read, write) = UnixStream::pair()?;    // 注冊用于處理信號的 pipe    if let Err(e) = pipe::register(SIGTERM, write) {        println!("failed to set SIGTERM signal handler {e:?}");    }    let mut fds = [        PollFd::new(inotify_fd.as_raw_fd(), PollFlags::POLLIN),        PollFd::new(read.as_raw_fd(), PollFlags::POLLIN),    ];    loop {        match poll(&mut fds, -1) {            Ok(polled_num) => {                if polled_num <= 0 {                    eprintln!("polled_num <= 0!");                    break;                }                if let Some(flag) = fds[0].revents() {                    if flag.contains(PollFlags::POLLIN) {                        // 得到 inotify 事件,進行處理                        let events = inotify_fd.read_events()?;                        for event in events {                            handle_event(event)?;                        }                    }                }                if let Some(flag) = fds[1].revents() {                    if flag.contains(PollFlags::POLLIN) {                        println!("received SIGTERM signal");                        break;                    }                }            }            Err(e) => {                if e == nix::Error::EINTR {                    continue;                }                eprintln!("Poll error {:?}", e);                break;            }        }    }    inotify_fd.rm_watch(wd)?;    Ok(())}fn handle_event(event: InotifyEvent) -> io::Result<()> {    let file_name = match event.name {        Some(name) => name,        None => return Ok(()),    };    let event_mask = event.mask;    let kind = if event_mask.contains(AddWatchFlags::IN_ISDIR) {        "directory"    } else {        "file"    };    println!(        "{} {} was {:?}.",        kind,        file_name.to_string_lossy(),        event_mask    );    Ok(())}

          編譯&測試:

          shell
          cargo build./target/debug/inotify test

          圖片

          可以看到,inotify 不會遞歸監(jiān)聽二級目錄下的文件dir1/file2.txt。

          經(jīng)測試,Inotify 可以直接監(jiān)聽容器 rootfs 下的目錄:

          shell
          nerdctl run --rm -it golang./target/debug/inotify /run/containerd/io.containerd.runtime.v2.task/default/CONTAINERD_ID/rootfs

          圖片

          Fanotify基本介紹

          Inotify 能夠監(jiān)聽目錄和文件的事件,但這種 notifiation 機制也存在局限:inotify 只能通知用戶態(tài)進程觸發(fā)了哪些文件系統(tǒng)事件,而無法進行干預(yù),典型的應(yīng)用場景是殺毒軟件。

          Fanotify[4] 的出現(xiàn)就是為了解決這個問題,同時允許遞歸監(jiān)聽目錄下的子目錄和文件。

          Fanotify 的工作流程如下:

          1. 用戶通過系統(tǒng)調(diào)用(如:write、read)操作文件;

          2. 內(nèi)核將文件系統(tǒng)事件發(fā)送到 fsnotify_group 的事件隊列中;

          3. 喚醒等待 fanotify 事件的進程(listener);

          4. 進程通過 fd 從內(nèi)核隊列讀取 fanotify 事件;

          5. 如果是 FAN_OPEN_PERM 和 FAN_ACCESS_PERM 監(jiān)聽類型,進程需要通過 write 把許可信息(允許 or 拒絕)寫回內(nèi)核;

          6. 內(nèi)核根據(jù)許可信息決定是否繼續(xù)完成該文件系統(tǒng)事件。

          監(jiān)監(jiān)聽容器中的文件系統(tǒng)事件 - abin在路上 - 博客園 (cnblogs.com)

          *博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。



          關(guān)鍵詞: fanotify

          技術(shù)專區(qū)

          關(guān)閉