VFS四大对象之四-struct file

时间:2021-05-10 08:47:02

继上一篇文章:

http://www.cnblogs.com/linhaostudy/p/7428971.html

四、file结构体

文件对象:注意文件对象描述的是进程已经打开的文件。因为一个文件可以被多个进程打开,所以一个文件可以存在多个文件对象。但是由于文件是唯一的,那么inode就是唯一的,目录项也是定的!

进程其实是通过文件描述符来操作文件的,注意每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。

 struct file {
struct list_head f_list;
struct dentry *f_dentry;
struct vfsmount *f_vfsmnt;
struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
int f_error; size_t f_maxcount;
unsigned long f_version; /* needed for tty driver, and maybe others */
void *private_data; /* preallocated helper kiobuf to speedup O_DIRECT */
struct kiobuf *f_iobuf;
long f_iobuf_lock;
};

f_list:所有的打开的文件形成的链表!注意一个文件系统所有的打开的文件都通过这个链接到super_block中的s_files链表中!

f_dentry:与该文件相关的dentry

f_vfsmnt:该文件在这个文件系统中的安装点

f_op:文件操作,当进程打开文件的时候,这个文件的关联inode中的i_fop文件操作会初始化这个f_op字段

f_count:引用计数

f_flags:打开文件时候指定的标识

f_mode:文件的访问模式

f_pos:目前文件的相对开头的偏移

unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin:预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数

f_owner:记录一个进程ID,以及当某些事发送的时候发送给该ID进程的信号

f_uid:用户ID

f_gid:组ID

f_error:写操作错误码

f_version:版本号,当f_pos改变时候,version递增

private_data:私有数据( 文件系统和驱动程序使用 )

重点解释一些重要字段

首先,f_flags、f_mode和f_pos代表的是这个进程当前操作这个文件的控制信息。这个非常重要,因为对于一个文件,可以被多个进程同时打开,那么对于每个进程来说,操作这个文件是异步的,所以这个三个字段就很重要了。

第二:对于引用计数f_count,当我们关闭一个进程的某一个文件描述符时候,其实并不是真正的关闭文件,仅仅是将f_count减一,当f_count=0时候,才会真的去关闭它。对于dup,fork这些操作来说,都会使得f_count增加,具体的细节,以后再说。

第三:f_op也是很重要的!是涉及到所有的文件的操作结构体。例如:用户使用read,最终都会调用file_operations中的读操作,而file_operations结构体是对于不同的文件系统不一定相同。里面一个重要的操作函数式release函数,当用户执行close时候,其实在内核中是执行release函数,这个函数仅仅将f_count减一,这也就解释了上面说的,用户close一个文件其实是将f_count减一。只有引用计数减到0才关闭文件。

注意:对于“正在使用”和“未使用”的文件对象分别使用一个双向链表进行管理。

注意上面的file只是对一个文件而言,对于一个进程(用户)来说,可以同时处理多个文件,所以需要另一个结构来管理所有的files!

即:用户打开文件表--->files_struct

 struct files_struct {
atomic_t count;
rwlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */
int max_fds;
int max_fdset;
int next_fd;
struct file ** fd; /* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
fd_set close_on_exec_init;
fd_set open_fds_init;
struct file * fd_array[NR_OPEN_DEFAULT];
};

解释一些字段:

count:引用计数

file_lock:锁,保护下面的字段

max_fds:当前文件对象的最大的数量

max_fdset:文件描述符最大数

next_fd:已分配的最大的文件描述符+1

fd:指向文件对象指针数组的指针,一般就是指向最后一个字段fd_arrray,当文件数超过NR_OPEN_DEFAULT时候,就会重新分配一个数组,然后指向这个新的数组指针!

close_on_exec:执行exec()时候需要关闭的文件描述符

open_fds:指向打开的文件描述符的指针

close_on_exec_init:执行exec()时候需要关闭的文件描述符初始化值

open_fds_init:文件描述符初值集合

fd_array:文件对象指针的初始化数组

注意上面的file和files_struct记录的是与进程相关的文件的信息,但是对于进程本身来说,自身的一些信息用什么表示,这里就涉及到fs_struct结构体。

   struct fs_struct {
atomic_t count;
rwlock_t lock;
int umask;
struct dentry * root, * pwd, * altroot;
struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;
};

解释一些字段:

count:引用计数

lock:保护锁

umask:打开文件时候默认的文件访问权限

root:进程的根目录

pwd:进程当前的执行目录

altroot:用户设置的替换根目录

注意:实际运行时,这三个目录不一定都在同一个文件系统中。例如,进程的根目录通常是安装于“/”节点上的ext文件系统,而当前工作目录可能是安装于/etc的一个文件系统,替换根目录也可以不同文件系统中。

rootmnt,pwdmnt,altrootmnt:对应于上面三个的安装点。