OS / Linux / 文件描述符以及 file 结构体

零、前言

程序可以理解为硬盘上的普通二进制文件;进程是加载到内存中的二进制文件,除了加载到内存中的二进制文件外,还附有所有对于该二进制文件描述信息的结构体,描述该进程的结构体叫PCB(进程控制块),在这就不在讨论。对于程序与进程,也就可以简单地理解为是否有PCB(进程控制块)。下面我们再来讨论 PCB 与 file_struct 的关系。

在每一个PCB中,都有一个文件描述符表,通过文件描述符索引指向 file 结构体 (系统打开文件表)

文件描述符在形式上是一个非负整数,实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表,当程序打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。也就是说,一个程序能够访问文件是因为给这个程序分配了文件描述符。

下面我们来讨论 file 结构体里面具体有哪些内容,file 结构体定义在 linux 系统中的(/kernels/include/linus/fs.h)文件中。

一、file 结构体

struct file
{
    union
    {
        struct list_head fu_list;   //文件对象链表指针 linux/include/linux/list.h 。
        struct rcu_head fu_rcuhead; //RCU(Read-Copy Update)是 Linux 2.6 内核中新的锁机制。
    } f_u;
    struct path f_path;           //包含 dentry 和 mnt 两个成员,用于确定文件路径。
#define f_dentry f_path.dentry    //f_path 的成员之一,当统的挂载根目录。
    const struct file_operations; //*f_op; 与该文件相关联的操作函数。
    atomic_t f_count;             //文件的引用计数(有多少进程打开该文件)。
    unsigned int f_flags;         //对应于 open 时指定的 flag 。
    mode_t f_mode;                //读写模式:open 的 mod_t mode 参数。
    off_t f_pos;                  //该文件在当前进程中的文件偏移量。
    struct fown_struct f_owner;   //该结构的作用是通过信号进行 I/O 时间通知的数据。
    unsigned int f_uid, f_gid;    //文件所有者 id,所有者组 id。
    struct file_ra_state f_ra;    //在 linux/include/linux/fs.h 中定义,文件预读相关。
    unsigned long f_version;
#ifdef CONFIG_SECURITY
    void *f_security;
#endif   
    void *private_data;
#ifdef CONFIG_EPOLL
    struct list_head f_ep_links;
    spinlock_t f_ep_lock;
#endif  
    struct address_space *f_mapping;
};

其中重要参数参数介绍如下:

f_flags:表示打开文件的权限。

f_pos:表示当前读写文件的位置。

f_count:这个是一个相对来说比较重要的参数,表示打开文件的引用计数,如果有多个文件指针指向它,就会增加 f_count 的值。

f_mode:设置对文件的访问模式,例如:只读,只写等。

当然其中还定义了许多结构体等内容,这里就不在深究,下面我们来讨论一个 fd 与 files_struct 的关系。files_struct 不同于 file 结构体。在这里要区分清楚。

二、file_operations

当我们打开一个文件时,操作系统为了管理所打开的文件,都会为这个文件创建一个 file 结构体,而 file 结构体中的 f_op 指针又指向 file_operations 结构体,这个结构体中的成员除了 struct module* owner 其余都是函数指针,file_operation 就是把系统调用和驱动程序关联起来的关键数据结构。这个结构的每一个成员都对应着一个系统调用。读取 file_operation 中相应的函数指针,接着把控制权转交给函数,从而完成了 Linux 设备驱动程序的工作。

我们先来看看 file_operations 结构体的实现和相关成员的介绍。

struct file_operations
{
    struct module *owner;
    //指向拥有该模块的指针;
    loff_t (*llseek)(struct file *, loff_t, int);
    //llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值.
    ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
    //用来从设备中获取数据. 在这个位置的一个空指针导致 read 系统调用以 -EINVAL("Invalid argument") 失败. 一个非负返回值代表了成功读取的字节数( 返回值是一个 "signed size" 类型, 常常是目标平台本地的整数类型).
    ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
    //发送数据给设备. 如果 NULL, -EINVAL 返回给调用 write 系统调用的程序. 如果非负, 返回值代表成功写的字节数.
    ssize_t (*aio_read)(struct kiocb *, const struct iovec *, unsigned long, loff_t);
    //初始化一个异步读 -- 可能在函数返回前不结束的读操作.
    ssize_t (*aio_write)(struct kiocb *, const struct iovec *, unsigned long, loff_t);
    //初始化设备上的一个异步写.
    int (*readdir)(struct file *, void *, filldir_t);
    //对于设备文件这个成员应当为 NULL; 它用来读取目录, 并且仅对**文件系统**有用.
    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 *);
    //mmap 用来请求将设备内存映射到进程的地址空间. 如果这个方法是 NULL, mmap 系统调用返回 -ENODEV.
    int (*open)(struct inode *, struct file *);
    //打开一个文件
    int (*flush)(struct file *, fl_owner_t id);
    //flush 操作在进程关闭它的设备文件描述符的拷贝时调用;
    int (*release)(struct inode *, struct file *);
    //在文件结构被释放时引用这个操作. 如同 open, release 可以为 NULL.
    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 *);
    //lock 方法用来实现文件加锁; 加锁对常规文件是必不可少的特性, 但是设备驱动几乎从不实现它.
    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 (*flock)(struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **);
};

 

文件描述符(file)是操作系统用来管理文件的数据结构,fd 就是 fd_array 的索引,FILE * 指针值就是该 fd_array 数组中元素的值,也就是 file 结构体的地址。

三、files_struct

每个进程用一个 files_struct 结构来记录文件描述符的使用情况,这个 files_struct 结构称为用户打开文件表,它是进程的私有数据

files_struct 结构在 include/linux/fdtable.h 中定义如下:

struct files_struct
{
    atomic_t count;     /* 共享该表的进程数 */
    rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/
    int max_fds;        /*当前文件对象的最大数*/
    int max_fdset;      /*当前文件描述符的最大数*/
    int next_fd;
    /*已分配的文件描述符加1 */
    struct file **fd;          /* 指向文件对象指针数组的指针 */
    fd_set *close_on_exec;     /*指向执行exec( )时需要关闭的文件描述符*/
    fd_set *open_fds;          /*指向打开文件描述符的指针*/
    fd_set close_on_exec_init; /* 执行exec( )时需要关闭的文件描述符的初 值集合*/
    fd_set open_fds_init;      /*文件描述符的初值集合*/
    struct file *fd_array[32]; /* 文件对象指针的初始化数组*/
};

 四、概括

 

参考:https://www.cnblogs.com/xiangtingshen/p/11961434.html

 

(SAW:Game Over!)

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值