继上一篇文章:
http://www.cnblogs.com/linhaostudy/p/7428971.html
四、file结构体
文件对象:注意文件对象描述的是进程已经打开的文件。因为一个文件可以被多个进程打开,所以一个文件可以存在多个文件对象。但是由于文件是唯一的,那么inode就是唯一的,目录项也是定的!
进程其实是通过文件描述符来操作文件的,注意每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。
565 struct file { 566 struct list_head f_list; 567 struct dentry *f_dentry; 568 struct vfsmount *f_vfsmnt; 569 struct file_operations *f_op; 570 atomic_t f_count; 571 unsigned int f_flags; 572 mode_t f_mode; 573 loff_t f_pos; 574 unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; 575 struct fown_struct f_owner; 576 unsigned int f_uid, f_gid; 577 int f_error; 578 579 size_t f_maxcount; 580 unsigned long f_version; 581 582 /* needed for tty driver, and maybe others */ 583 void *private_data; 584 585 /* preallocated helper kiobuf to speedup O_DIRECT */ 586 struct kiobuf *f_iobuf; 587 long f_iobuf_lock; 588 };
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
172 struct files_struct { 173 atomic_t count; 174 rwlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ 175 int max_fds; 176 int max_fdset; 177 int next_fd; 178 struct file ** fd; /* current fd array */ 179 fd_set *close_on_exec; 180 fd_set *open_fds; 181 fd_set close_on_exec_init; 182 fd_set open_fds_init; 183 struct file * fd_array[NR_OPEN_DEFAULT]; 184 };
解释一些字段:
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结构体。
5 struct fs_struct { 6 atomic_t count; 7 rwlock_t lock; 8 int umask; 9 struct dentry * root, * pwd, * altroot; 10 struct vfsmount * rootmnt, * pwdmnt, * altrootmnt; 11 };
解释一些字段:
count:引用计数
lock:保护锁
umask:打开文件时候默认的文件访问权限
root:进程的根目录
pwd:进程当前的执行目录
altroot:用户设置的替换根目录
注意:实际运行时,这三个目录不一定都在同一个文件系统中。例如,进程的根目录通常是安装于“/”节点上的ext文件系统,而当前工作目录可能是安装于/etc的一个文件系统,替换根目录也可以不同文件系统中。
rootmnt,pwdmnt,altrootmnt:对应于上面三个的安装点。