fd (File descriptor)
中文名叫做:文件描述符。文件描述符是一个非负整数,本质上是一个索引值。
先简单介绍一些结构体
task_struct
struct task_struct {
// ...
struct files_struct *files;
// ...
}
files_struct
/*
* Open file table structure
*/
struct files_struct {
// 读相关字段
atomic_t count;
bool resize_in_progress;
wait_queue_head_t resize_wait;
// 打开的文件管理结构
struct fdtable __rcu *fdt;
struct fdtable fdtable;
// 写相关字段
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 * fd_array[NR_OPEN_DEFAULT];
};
fdtable
struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; /* current fd array */
};
file
struct file {
// ...
struct path f_path;
struct inode *f_inode;
const struct file_operations *f_op;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
// ...
}
- 每个进程都是由task_struct来管理,当我们对一个fd进行操作时,首先系统根据task_struct的 成员变量files找到files_struct,
file_struct中有 struct fdtable fdtable和 struct file * fd_array[NR_OPEN_DEFAULT],它们两个都是管理file的,只不过
struct file * fd_array[NR_OPEN_DEFAULT]是一个静态数组,在 64 位系统上,它的大小为 64;
struct fdtable 这个是一个动态数组,数组边界是用字段描述的;(这样是性能和资源的权衡 !大部分进程只会打开少量的文件,所以静态数组就够了,这样就不用另外分配内存。如果超过了静态数组的阈值,那么就动态扩展。)
- fdtable 的struct file __rcu **fd; 是一个二级指针,它实际是指向一个数组,数组元素为指针(指针类型为 struct file *),而fd就是这个file_rcu的下标。我们再通过这个file找到这个文件对应的inode。
inode是索引节点,它是操作系统为了屏蔽不同文件系统差异而虚拟出来的文件虚拟系统(VFS)的一部分。
每个inode都有一个号码,操作系统用inode号码来识别不同的文件。
,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。
表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。