欢迎登陆真网站,您的到来是我们的荣幸。 登陆 注册 忘记密码? ☆设为首页 △加入收藏
欢迎加入真幸福QQ群
电脑知识: 基础知识 网络技术 操作系统 办公软件 电脑维修 电脑安全 windows7 windows8 windows10 服务器教程 平板电脑 视频播放教程 网络应用 互联网 工具软件 浏览器教程 QQ技巧 输入法教程 影视制作 YY教程 wps教程 word教程 Excel教程 PowerPoint
云南西双版纳特产小花糯玉米真空包装


Win7电脑安装了网卡之后就无法发声了怎么办?
兼谈在Win8上安装Linux
Hadoop 参数配置优化
图图桌面美化软件的添加分组功能介绍
Godaddy主机快速安装Zen Cart程序建立网站教程
ubuntu 看迅雷电影的方法
关闭win7系统休眠功能的具体方法
win7系统主页卫士如何快速删除
利用VirtualBox本地电脑安装虚拟系统设置
Windows Server 2003 R2停止服务.bat
Linux内核中的文件描述符
【 来源:网络 】【 点击:1 】 【 发布时间:2017_03_03 08:59:59 】

  Kernel version:2.6.14

  CPU architecture:ARM920T

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

  1、文件对象

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

struct file {
 struct list_head f_list;         //所有打开文件的链表
 struct dentry  *f_dentry;      //文件的dentry
 struct vfsmount         *f_vfsmnt;      //文件目录的VFS安装点指针
 struct file_operations *f_op;          //指向文件操作函数集的指针
 atomic_t  f_count;        //记录访问本文件的进程数目的计数器
 unsigned int   f_flags;        //访问类型
 mode_t   f_mode;         //访问模式
 loff_t   f_pos;          //文件当前的读写位置
 struct fown_struct f_owner;
 unsigned int  f_uid, f_gid;   //文件所有者ID和用户组ID
 struct file_ra_state f_ra;

 unsigned long  f_version;
 void   *f_security;

 /* needed for tty driver, and maybe others */
 void   *private_data;

#ifdef CONFIG_EPOLL
 /* Used by fs/eventpoll.c to link all the hooks to this file */
 struct list_head f_ep_links;
 spinlock_t  f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
 struct address_space *f_mapping;
 struct rcu_head  f_rcuhead;
};

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

  ● 文件所有者;

  ● 同组用户;

  ● 其他用户。

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

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

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

 struct file_operations {
 struct module *owner;
 loff_t (*llseek) (struct file *, loff_t, int);
 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
 int (*readdir) (struct file *, void *, filldir_t);
 unsigned int (*poll) (struct file *, struct poll_table_struct *);
 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
 int (*mmap) (struct file *, struct vm_area_struct *);
 int (*open) (struct inode *, struct file *);
 int (*flush) (struct file *);
 int (*release) (struct inode *, struct file *);
 int (*fsync) (struct file *, struct dentry *, int datasync);
 int (*aio_fsync) (struct kiocb *, int datasync);
 int (*fasync) (int, struct file *, int);
 int (*lock) (struct file *, int, struct file_lock *);
 ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
 ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 int (*check_flags)(int);
 int (*dir_notify)(struct file *filp, unsigned long arg);
 int (*flock) (struct file *, int, struct file_lock *);
};

  从上面的代码可以看到,结构中是一系列函数的指针,这里有我们比较熟悉的read、open、write和close等函数的指针。进程就是通过这些函数访问一个文件的,file_operations是linux虚拟文件系统VFS和进程之间的接口。

  2、文件描述符

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

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

  3、进程打开文件表

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

  /*

  * Open file table structure

  */

  struct files_struct {

  atomic_t count; //引用计数

  spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */

  struct fdtable *fdt; //管理文件描述符

  struct fdtable fdtab; //管理文件描述符

  fd_set close_on_exec_init; //位图

  fd_set open_fds_init; //位图

  struct file * fd_array[NR_OPEN_DEFAULT]; //文件描述符数组

  };

  显然,这个结构应该属于进程的私有数据,所以进程控制块task_struct用指针files指向它。

  struct task_struct {

  ...

  /* open file information */

  struct files_struct *files;

  ...

  };

  进程与其打开文件之间的关系如下图所示。

  4、文件描述符的管理

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

  struct fdtable {

  unsigned int max_fds; //可以代开的最大文件数

  int max_fdset; //位图的最大长度

  int next_fd; //下一个可用的fd

  struct file ** fd; /* current fd array 指向files_struct的fd_array */

  fd_set *close_on_exec;

  fd_set *open_fds; //打开的文件标记,比如第2位为0,则打开了2号文件

  struct rcu_head rcu;

  struct files_struct *free_files;

  struct fdtable *next;

  };

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

本网站由川南居提供技术支持,fkzxf版权所有 浙ICP备12031891号
淳安分站 淳安分站