Linux内核中的文件描述符

  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的管理。

时间: 2024-12-01 08:27:47

Linux内核中的文件描述符的相关文章

mingw-MinGW编译环境中由文件描述符(fd)获得windows文件句柄有什么方法

问题描述 MinGW编译环境中由文件描述符(fd)获得windows文件句柄有什么方法 我在MinGW中打开了一个文件后把描述出输出来是3,推测MinGW中不是用的文件句柄表示open打开的文件,现在想从这个描述符中获取windows句柄,有什么函数可以实现吗

linux系统中各个文件描述——陆续添加

1./etc/inputrc 通过设置INPUTRC环境变量(参见/etc/profile文件),其作用主要定义或者改变一些功能键的定义,从而更好地使用命令行,通常情况下INPUTRC环境变量指向 /etc/inputrc文件,只要编辑/etc/inputrc文件,以及利用Tab键的命令补全功能,就可以实现类似于MSDOS的DOSKEY的功能. 以Redhat 7.3为例来说明,使用的bash shell版本号为2.0.5.你可以根据自己的需要定制与修改此文件,如想了解更多的内容,可以参阅man

在Linux内核中读写文件

http://blog.csdn.net/tommy_wxie/article/details/8193954 http://blog.csdn.net/tommy_wxie/article/details/8194276

linux中文件描述符fd和文件指针flip的理解

整理自:http://www.cnblogs.com/Jezze/archive/2011/12/23/2299861.html 简单归纳:fd(file descriptor)只是一个整数,在open时产生.起到一个索引的作用.每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指向已打开文件的指针,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp. 文件描述符的操作(如:

linux系统编程基础(三)文件描述符file descriptor与inode的相关知识

每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的 信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块 (PCB,Process Control Block).task_struct中有一个指针(struct files_struct *files; )指向files_struct结构体,称为文件 描述符表,其中每个表项包含一个指向已打开的文件的指针,如下图所示. 用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述

Linux下利用文件描述符恢复的成功失败实验

    数据误删除是作为初级运维人员常常遇到的"低级错误",一些有经验的老手有时也在疲劳.不冷静的情况下"马失前蹄".一旦误删除数据文件,尽快采用影响最小.最迅速的手段恢复数据库是第一要务. 恢复数据的方法很多,比如冷热备份.闪回数据库等等,如果是直接从操作系统OS层面删除数据文件,在Linux/Unix环境下,有一些优选手段可以使用.其中之一就是文件描述符(File Description).   1.聊聊File Description   不同的操作系统,在实

文件句柄(file handles) & 文件描述符(file descriptors)

1.概述 在实际工作中会经常遇到一些bug,有些就需要用到文件句柄,文件描述符等概念,比如报错: too many open files, 如果你对相关知识一无所知,那么debug起来将会异常痛苦.在linux操作系统中,文件句柄(包括Socket句柄).打开文件.文件指针.文件描述符的概念比较绕,而且windows的文件句柄又与此有何关联和区别?这一系列的问题是我们不得不面对的. 博主通过翻阅相关资料,并采用了一些demo来验证相关观点.如果文中有理解偏差,欢迎指正,对linux内核不是很熟,

文件描述符-关于Linux中的dup2()

问题描述 关于Linux中的dup2() UNIX高级编程中,第三章习题中说道:dup(fd0);dup(fd1);dup(fd2);if (fd >2)close(fd);为什么当fd > 2时需要关闭?我查找了答案,说是当fd为3时,有4个文件描述符指向同一文件表项,所以要关闭3,难道同一个文件表项的最大只支持3个文件描述符? 解决方案 首先,上面应该是dup2(fd0);dup2(fd1);dup2(fd2);这样做的是重定向0.1.2(即标准输入.输出.出错)到一个fd中. 明白了上面

Linux中通过Socket文件描述符寻找连接状态介绍

  Proc虚拟文件系统下面有许多数字命名的子目录,这些数字表示系统当前运行的进程号; 其中/proc/N/fd目录下面保存了打开的文件描述符,指向实际文件的一个链接.如下: 代码如下: [root@XXXXXXX_10_1_17_138 song_test]# ll /proc/25465/fd total 0 lrwx------ 1 root root 64 Apr 14 09:36 0 -> /dev/pts/4 (deleted) lrwx------ 1 root root 64 A