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

Kernel version:2.6.14

CPU architecture:ARM920T

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

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

1.文件对象

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

[plain] view plain copy print?

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,该结构封装了对文件进行操作的函数,定义如下:

[plain] view plain copy print?

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,其定义如下:

[plain] view plain copy print?

/* * 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指向它。

[plain] view plain copy print?

struct task_struct { ... /* open file information */ struct files_struct *files; ... };

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

4.文件描述符的管理

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

[plain] view plain copy print?

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

责任编辑:

Linux中文件描述符1,linux内核中的文件描述符(一)--基础知识简介相关推荐

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

    linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.cs ...

  2. modprobe:用于向内核中加载模块或者从内核中移除模块。

    modprobe:用于向内核中加载模块或者从内核中移除模块. modprobe br_netfilter 加载模块 modprobe -r br_netfilter 移除 1.查看系统中所有modul ...

  3. modprobe命令用于智能地向内核中加载模块或者从内核中移除模块

    modprobe命令用于智能地向内核中加载模块或者从内核中移除模块. modprobe可载入指定的个别模块,或是载入一组相依的模块.modprobe会根据depmod所产生的相依关系,决定要载入哪些模 ...

  4. IT:后端进阶技术路线图(初级→中级→高级)、后端开发工程师(技术方向分类之后台业务开发/中间件/内核/分布式架构)基础知识简介、技术路线/技术趋势指南(如何选择自己的技术方向)之详细攻略

    IT:后端进阶技术路线图(初级→中级→高级).后端开发工程师(技术方向分类之后台业务开发/中间件/内核/分布式架构)基础知识简介.技术路线/技术趋势指南(如何选择自己的技术方向)之详细攻略 目录 后端 ...

  5. html中table标签、tr标签、th标签、td标签的基础知识

    html中table标签.tr标签.th标签.td标签的基础知识 表格的结构 表格的基本标签 表格标签的基本属性 table标签的基本属性 tr标签的基本属性 th和td标签的基本属性 表格高级样式设 ...

  6. 简述linux内核中,Linux内核中的文件描述符(一)——基础知识简介

    2.文件描述符 下面进一步介绍进程对自己所访问的file对象的管理方法.linux中使用一个数组来管理进程打开的文件的file对象,数组中的每个元素都存放一个纸箱进程所打开的文件的file对象.既然用 ...

  7. linux内核中的 哈希表_Linux内核中的设备模型及SCSI示例解析

    关于硬件架构 想要了解Linux操作系统的内核设备和驱动模型,最好先了解一下现在计算机硬件的架构.对计算机硬件有一定了解之后,对理解Linux内核中的设备和驱动模型非常有帮助.如图1是常规计算机的硬件 ...

  8. linux c++ 获取当前时间毫秒_Linux内核中的形形色色的“钟表”,你了解多少?

    如果Linux也是一个普通人的话,那么她的手腕上应该有十几块手表,包括:CLOCK_REALTIME.CLOCK_MONOTONIC.CLOCK_PROCESS_CPUTIME_ID.CLOCK_TH ...

  9. Linux设备驱动开发详解【二】_设备驱动相关硬件基础知识

    本文简介 本文讲解底层驱动工程师必备的硬件基础,给出了嵌入式系统硬件原理及分析方法的全景视图.         2.1 节讲解微控制器.微处理器.数字信号处理器以及应用于特定领域的处理器各自的特点. ...

最新文章

  1. php查找多个字符串替换,php 替换多个字符串
  2. 科目三电子考的通过率普遍偏低
  3. 深圳宝安图书馆官网错误 HTTP Status 500 - Servlet.init() for servlet spring threw exception...
  4. 【图像修复】基于matlab GUI运动模糊消除(逆滤波)【含Matlab源码 847期】
  5. [Windows] 【直播放映馆V9.0】Bilibili,斗鱼,虎牙,企鹅电竞,音乐电台,无广告看电影直播!...
  6. java wed汽车4s店销售管理系统
  7. MySQL中怎么对varchar类型排序问题(数字字符串和汉字拼音的顺序)
  8. java倒计时器_Java并发系列5--倒计时器CountDownLatch
  9. 仰望星空不如脚踏实地
  10. EXCEL中进行经纬度坐标排重
  11. Unity FairyGUI(十二)
  12. WPS表格转换成Excel用什么方法
  13. BZOJ 2069: [POI2004]ZAW(Dijkstra + 二进制拆分)
  14. Error occured processing XML 'Cannot find class [springmvc.extention.BeanArgumentResolver]'.
  15. 单位根检验、协整检验和格兰杰因果检验三者之间的关系
  16. 创客学院线上培训课程泄露,大家抓紧白嫖!
  17. 【内有福利】5.7K画质高品质防抖:运动全景相机开启新纪元
  18. 【全套完整版本】YOLOv3使用方法记录
  19. 墨尔本大学计算机科学世界排名,墨尔本大学世界排名及专业排名汇总(QS世界大学排名版)...
  20. disconf原理 “入坑”指南

热门文章

  1. jquery 封装页面之间获取值
  2. RT/Metro商店应用如何如何获取图片的宽高
  3. 关于final局部变量引用的研究
  4. 正式入住博客园----附07年写的短评,虽然稚嫩但已实现,那年我大三。
  5. 使用PowerDesigner创建数据库表
  6. linux shell find命令 查找指定时间范围内的文件
  7. mysql max_allowed_packet 参数 限制接受的数据包大小
  8. python3 中的编码问题 unicode, utf-8, gbk, ascii
  9. curl: (25) Failed FTP upload: 550 解决办法
  10. golang import 导入包语法介绍 点 别名 下划线