新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > linux内核中的文件描述符(一)--基础知识简介

linux内核中的文件描述符(一)--基础知识简介

作者: 时间:2016-11-22 来源:网络 收藏
Kernel version:2.6.14

CPU architecture:ARM920T

本文引用地址:https://www.eepw.com.cn/article/201611/319997.htm

Author:ce123(http://blog.csdn.net/ce123)

作为文件的使用者,进程理所当然的要将所使用的文件记录于自己的控制块中,也就是task_struct。另外,由于进程所对应的程序也是一个文件,因此进程控制块还必须记录这个文件的相关信息。由于OS要对所有进程提供服务,因此OS还要维护一个记录所有进程打开的文件的总表。

1.文件对象

当进程通过open系统调用打开一个文件时,该系统调用找到这个文件后,会把文件封装到一个file结构的实例中提供给进程,这个实例称为file对象。file结构的定义如下:

[plain]view plaincopy
print?
  1. structfile{
  2. structlist_headf_list;//所有打开文件的链表
  3. structdentry*f_dentry;//文件的dentry
  4. structvfsmount*f_vfsmnt;//文件目录的VFS安装点指针
  5. structfile_operations*f_op;//指向文件操作函数集的指针
  6. atomic_tf_count;//记录访问本文件的进程数目的计数器
  7. unsignedintf_flags;//访问类型
  8. mode_tf_mode;//访问模式
  9. loff_tf_pos;//文件当前的读写位置
  10. structfown_structf_owner;
  11. unsignedintf_uid,f_gid;//文件所有者ID和用户组ID
  12. structfile_ra_statef_ra;
  13. unsignedlongf_version;
  14. void*f_security;
  15. /*neededforttydriver,andmaybeothers*/
  16. void*private_data;
  17. #ifdefCONFIG_EPOLL
  18. /*Usedbyfs/eventpoll.ctolinkallthehookstothisfile*/
  19. structlist_headf_ep_links;
  20. spinlock_tf_ep_lock;
  21. #endif/*#ifdefCONFIG_EPOLL*/
  22. structaddress_space*f_mapping;
  23. structrcu_headf_rcuhead;
  24. };

结构中的域f_uid为文件所有者的ID,f_gid为文件所有者所在组的ID。这样就使得一个文件可能面临三种用户的访问:

  • 文件所有者;
  • 同组用户;
  • 其他用户。

内核在处理一个进程或用户访问一个文件的请求时,要根据进程的f_uid和f_gid以及访问模式来确定该进程是否具有访问这个文件的权限。对于一个用户来说,可以有读、写和执行三种文件权限,这三种权限和三种用户就共有9中组合,即文件的访问权限可以用9个bit来表示,并将其保存在文件的dentry中。

结构中的域f_pos记录了进程对文件读写位置的当前值,可以通过调用函数llseek进程移动。

结构中的f_op执向结构file_operations,该结构封装了对文件进行操作的函数,定义如下:

[plain]view plaincopy
print?
  1. structfile_operations{
  2. structmodule*owner;
  3. loff_t(*llseek)(structfile*,loff_t,int);
  4. ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);
  5. ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t);
  6. ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);
  7. ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,loff_t);
  8. int(*readdir)(structfile*,void*,filldir_t);
  9. unsignedint(*poll)(structfile*,structpoll_table_struct*);
  10. int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);
  11. long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong);
  12. long(*compat_ioctl)(structfile*,unsignedint,unsignedlong);
  13. int(*mmap)(structfile*,structvm_area_struct*);
  14. int(*open)(structinode*,structfile*);
  15. int(*flush)(structfile*);
  16. int(*release)(structinode*,structfile*);
  17. int(*fsync)(structfile*,structdentry*,intdatasync);
  18. int(*aio_fsync)(structkiocb*,intdatasync);
  19. int(*fasync)(int,structfile*,int);
  20. int(*lock)(structfile*,int,structfile_lock*);
  21. ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);
  22. ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);
  23. ssize_t(*sendfile)(structfile*,loff_t*,size_t,read_actor_t,void*);
  24. ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);
  25. unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);
  26. int(*check_flags)(int);
  27. int(*dir_notify)(structfile*filp,unsignedlongarg);
  28. int(*flock)(structfile*,int,structfile_lock*);
  29. };
从上面的代码可以看到,结构中是一系列函数的指针,这里有我们比较熟悉的read、open、write和close等函数的指针。进程就是通过这些函数访问一个文件的,file_operations是linux虚拟文件系统VFS和进程之间的接口。

2.文件描述符

下面进一步介绍进程对自己所访问的file对象的管理方法。linux中使用一个数组来管理进程打开的文件的file对象,数组中的每个元素都存放一个纸箱进程所打开的文件的file对象。既然用一个数组来存放file对象,那么用数组的下标来访问文件就是一件顺理成章的方法,于是,linux就把数组元素的下标叫做该数组元素所对应的文件的文件描述符,该描述符就是系统对文件的标识,这个数组也叫文件描述符数组,如下图所示:

内核通过系统调用dup、dup2和fctl可以使数组中的多个元素指向同一个文件的file对象,也就是说,在linux中,同一个文件可以有多个文件描述符。

3.进程打开文件表

进程描述符数组中存放了一个进程所访问的所有文件,把这个文件描述符数组和这个数组在系统中的一些动态信息组合到一起,就形成了一个新的数据结构——进程打开文件表,即file_struct,其定义如下:

[plain]view plaincopy
print?
  1. /*
  2. *Openfiletablestructure
  3. */
  4. structfiles_struct{
  5. atomic_tcount;//引用计数
  6. spinlock_tfile_lock;/*Protectsallthebelowmembers.Nestsinsidetsk->alloc_lock*/
  7. structfdtable*fdt;//管理文件描述符
  8. structfdtablefdtab;//管理文件描述符
  9. fd_setclose_on_exec_init;//位图
  10. fd_setopen_fds_init;//位图
  11. structfile*fd_array[NR_OPEN_DEFAULT];//文件描述符数组
  12. };
显然,这个结构应该属于进程的私有数据,所以进程控制块task_struct用指针files指向它。

[plain]view plaincopy
print?
  1. structtask_struct{
  2. ...
  3. /*openfileinformation*/
  4. structfiles_struct*files;
  5. ...
  6. };
进程与其打开文件之间的关系如下图所示。

4.文件描述符的管理

file_struct中的fdt和fdtab用于管理文件文件描述符,一个是fdtable类型,另一个是其指针类型。fdtable的定义如下:

[plain]view plaincopy
print?
  1. structfdtable{
  2. unsignedintmax_fds;//可以代开的最大文件数
  3. intmax_fdset;//位图的最大长度
  4. intnext_fd;//下一个可用的fd
  5. structfile**fd;/*currentfdarray指向files_struct的fd_array*/
  6. fd_set*close_on_exec;
  7. fd_set*open_fds;//打开的文件标记,比如第2位为0,则打开了2号文件
  8. structrcu_headrcu;
  9. structfiles_struct*free_files;
  10. structfdtable*next;
  11. };

下图可以很直观的说明文件描述符fd的管理。




评论


技术专区

关闭