每个进程都有自己的根目录和当前工作目录,内核使用struct fs_struct来记录这些信息,进程描述符的fs字段便是指向该进程的fs_struct结构。

fs_struct 定义于 include/linux/fs_struct.h

struct fs_struct {
    int users;
    spinlock_t lock;
    seqcount_t seq;
    int umask;
    int in_exec;
    struct path root, pwd;
 };

除了根目录和当前工作目录,进程还需要记录自己打开的文件。进程已经打开的所有文件使用struct files_struct来记录,进程描述符的files字段便指向该进程的files_struct结构。

files_struct 定义于 include/linux/fdtable.h.

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;
    int next_fd;
    unsigned long close_on_exec_init[1];
    unsigned long open_fds_init[1];
    struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};

由于NR_OPEN_DEFAULTx86结构下的定义为32,在ia64结构下的定义为64,所以说,fd_array最多只能存储3264个文件对象,远远小于进程被允许打开的最大文件数NR_OPEN, 如果超过了NR_OPEN_DEFAULT, 多出来的文件对象将如何存储呢?

显然,内核必须分配新的存储空间存放这些文件对象的指针。旧版本的内核中,struct file_struct中有一个fd字段,指向文件对象的指针数组。通常fd指向fd_array,如果进程打开的文件数目多于32个,内核就分配一个新的更大的文件对象的指针数组,并将其地址存放在fd字段中,这个数组所包含的元素数目存放在max_fds字段。

新版本的内核将fdmax_fds以及其他几个相关字段组织在一起,增加一个新的独立数据结构struct fdtable,成为文件描述符表,其主要数据结构定义如下所示:

fdtable 定义于 include/linux/fdtable.h

struct fdtable {
    unsigned int max_fds;
    struct file __rcu **fd;      /* current fd array */
    unsigned long *close_on_exec;
    unsigned long *open_fds;
    struct rcu_head rcu;
};