9

Linux 的 file descriptor 筆記

 3 years ago
source link: https://kkc.github.io/2020/08/22/file-descriptor/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

說來慚愧,一直以來都在跟 Linux 打交道,也瞭解 everything in unix is a file 的概念,卻沒有真的好好理解 file descriptor 的基本結構是怎樣,但是在知乎上面看到這篇 Linux file descriptor 演進史,讓我對於他為什麼長這樣有更進一步的認識。(其實原本想找找英文資料,不過這篇講歷史的還蠻清楚的)

基本上這篇文章會筆記目前新版的 file descriptor 結構,也會延伸一些其他看到的資料,基於我對於 Linux kernel 並不是專家,如果有錯的地方希望大家能夠指正。

file descriptor

file descriptor (fd) 基本上是一層介面,可以讓我們去操作 file 和其他 input/output interface (例如 pipe & socket)。

kernel 內的基本結構

  • 每個 process 裡面包含 file descriptor 的 table。
  • file descriptor 其實只是個指標,指向系統層面 (system-wide) 的 openfile table 的 entry ,而這個 openfile table 在 Posix 裡面稱為 open file description。
  • fd_table 內的 inode_ptr 在去指向 i-node table 內的 entry。

file descriptor 和 file 之間的關係並不是一對一的。

relationship.png
圖從這個投影片來的 lusp_fileio_slides.pdf,另外要大推作者的書 The Linux Programming Interface,非常值得收藏

對應的 data structure source code

  1. process task_struct 裡面有 file_struct 成員,基本上需要從這個 file_struct 裡面找到對應的 file descriptor。file_struct 的成員原本是直接在 task_struct 內的,現在將它獨立起來,並用指標去存取,主要是因為 linux 在支援 thread 之後,需要以 task_struct 為 thread 單位,可以透過指標共用 file_struct 這種資源。

    1
    2
    3
    4
    5
    struct task_struct {
    ...
    struct files_struct *files;
    ...
    }
  2. files_struct 裡面可以找到 per process fdtable (file descriptor table),其中使用了很厲害的 RCU 技術,主要是針對讀多寫少的情況下,提升存取寫入 fdtable 效能。
    (struct fdtable in include/linux/fdtable.h)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    struct files_struct {
    /*
    * read mostly part
    */
    atomic_t count;
    bool resize_in_progress;
    wait_queue_head_t resize_wait;

    struct fdtable __rcu *fdt;
    struct fdtable fdtab;
    /*
    * written part on a separate cache line in SMP
    */
    spinlock_t file_lock ____cacheline_aligned_in_smp;
    unsigned int next_fd;
    unsigned long close_on_exec_init[1];
    unsigned long open_fds_init[1];
    unsigned long full_fds_bits_init[1];
    struct file __rcu * fd_array[NR_OPEN_DEFAULT];
    };

    struct fdtable {
    unsigned int max_fds;
    struct file __rcu **fd; /* current fd array */
    unsigned long *close_on_exec;
    unsigned long *open_fds;
    unsigned long *full_fds_bits;
    struct rcu_head rcu;
    };
  3. open file table 也稱為 open file descriptions,是系統層級的 table (https://github.com/torvalds/linux/blob/master/include/linux/fs.h#L921),這個 struct 定義了一些蠻重要的資料像是 file_offset, file_status, 還有最重要的 inode_ptr 去指向對應的 inode。

    1
    2
    3
    4
    5
    6
    7
    8
    struct file {
    union {
    struct llist_node fu_llist;
    struct rcu_head fu_rcuhead;
    } f_u;
    struct path f_path;
    struct inode *f_inode; /* cached value */
    const struct file_operations *f_op;
  4. open file table 在指向 system-wide 的 inode-table (https://github.com/torvalds/linux/blob/master/include/linux/fs.h#L615),其中的 i_mode 就記錄了對應的是哪一種檔案類型。

    1
    2
    3
    4
    5
    6
    struct inode {
    umode_t i_mode;
    unsigned short i_opflags;
    kuid_t i_uid;
    kgid_t i_gid;
    unsigned int i_flags;

一些常見的 fd 操作

  • 同一個 process 內通常透過 dup() or dup2() 可以複製 file descriptor,而兩個 fd 就可以指向同一筆 openfile entry (也就是同一個 file)
  • 不同 process 透過 fork() 也會拿到各自的 file descriptor,去指向同一筆 openfile entry
  • 不同 process 去開啟同一份檔案,會用各自的 file descriptor 指向不同的 openfile entry,但最後會指向同一份 inode

其他的經驗分享

在沒有了解 fd 的時候其實在寫程式上面犯了不少錯,像是在曾經在寫一個 socket programming 時,在 main process 內 fork child process ,但是卻沒有使用 close-on-exec flag ,所以把 main process 打開的 fd 也帶過去給 child,所以就算在 main process 去 close socket,對於那個被 child 抓住的 socket 還是沒被釋放,所以就看到前面的 LB 說後端的連線數量沒有下降,接著因為 rate limiting 的緣故,就把外面的連線給擋住了,而其實這時候後端還閒著很,這就是不熟悉 fd 行為而種下的雷,在理解了 fd 後,接著會再做一些筆記來談談 epoll & scm_right 之類的東西怎麼運作的,了解 fd 對於我們寫程式真的蠻重要的啊!

Reference:

圖片從https://unsplash.com/photos/o6GEPQXnqMY



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK