一.iNode节点
通常情况下,文件系统会将文件的实际内容和属性分开存放:
- 文件的属性保护在iNode节点中,每个iNode都有自己的编号.每个文件各占用一个iNode.不仅如此,iNode中还记录着文件数据所在的block块的编号
- 文件的实际内容保存在block中(数据块),每个block也有属于自己的编号.
- super block(超级块)用于记录整个文件系统的整体信息.包括:iNode和block的总量,已经使用量和剩余量,以及文件系统的格式和相关信息
每个inode都有一个号码,操作系统用inode号码来识别不同的文件。Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。
二.文件描述符表
1.每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的信息,称为进程描述符(进程控制块).
struct task_struct{
...
//打开文件信息
struct files_struct* files;
...
}
task_struct结构体中有一个指针(struct files_struct* files)指向files_struct结构体,称为文件描述符表.
文件描述符表记录着该进程打开的所有文件.files_struct结构体中 struct file* fd[NR_OPEN_DEFAULT]为struct file结构体数组,该数组中的每个元素指向已打开的文件的指针.
(已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体)
struct files_struct{
atomic_t count; //引用计数
struct fdtable* fdt;
struct fdtable fdtab;
spinlock_t file_lock ____cacheline_aligned_in_smp;
int next_fd;
struct embedded_fd_set close_on_exec_init;
struct embedded_fd_set open_fds_init;
struct file* fd_array[NR_OPEN_DEFAULT]; //文件描述符数组
}
struct file{
mode_t f_mode; //操作文件的权限(是否可读或可写)
dev_t f_rdev; //用于/dev/tty
off_t f_ops;//当前文件位移
unsigned short f_flags;//文件标志: O_RDONLY,O_NONBLOCK,0_SYNC
unsigned short f_count;//打开的文件数目
unsigned short f_readda;
struct inode* f_inode; //指向iNode的结构指针
struct file_operations* f_op; //文件操作索引指针
};
(2).用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述符表的索引(即0,1,2...),这些索引就称为文件描述符.
- 文件描述符:是open系统调用内部由操作系统自动分配的,操作系统分配这个fd时也不是随意分配的. 操作系统规定:fd从0开始依次增加. 文件描述符表其实就是一个数组,fd是index,文件表指针是value.
- 分配文件描述符的规则:最小未被使用
- 文件描述符中0,1,2已经默认被系统占用,分别是:标准输入(stdin),标准输出(stdout),标准错误(stderr)
三.文件表
struct file{
mode_t f_mode; //操作文件的权限(是否可读或可写)
dev_t f_rdev; //用于/dev/tty
off_t f_ops;//当前文件位移
unsigned short f_flags;//文件标志: O_RDONLY,O_NONBLOCK,0_SYNC
unsigned short f_count;//打开的文件数目
unsigned short f_readda;
struct inode* f_inode; //指向iNode的结构指针
struct file_operations* f_op; //文件操作索引指针
};
内核为所有打开文件维护一张文件表项,每个文件表项包含内容可以由以上结构体看出:
- 文件状态
- 当前文件偏移量
- 指向该文件i节点的指针
- 指向该文件操作的指针