struct file是Linux文件系统中的一个重要数据结构,用于表示进程打开的文件,也就是文件对象,struct file是已打开的文件在内存中的表示,存储了与文件操作和状态相关的信息。
通过file对象就可以获取当前文件的目录项和索引节点,通过files_struct这个纽带,就把进程了和文件系统对接起来了。那么文件系统给进程呈现的是什么信息呢?
一、文件对象结构体
上面说了struct file表示进程的打开的文件,所以这个结构体是在内存中构造出来的,所以呢它只有内存结构。
一个物理文件可以被打开多次,可以被多个进程打开,所以一个物理文件可能对应多个文件对象,但是一个文件对象肯定属于某一个物理文件,也就是说一个文件对象对应一个索引节点和目录项,但是一个索引节点和目录项,可能有多个打开的文件对象。
以下是完整的stuct file结构体,里面包含了链表、f_path、索引节点、以及操作表等。
struct file {
union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;
/*
* Protects f_ep, f_flags.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
enum rw_hint f_write_hint;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* 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 hlist_head *f_ep;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
errseq_t f_wb_err;
errseq_t f_sb_err; /* for syncfs */
} __randomize_layout
__attribute__((aligned(4)));
字段 | 涵义 | 使用说明 |
fu_llist | 文件链表节点 | 用于将当前打开的文件链入全局文件链表delayed_fput_list |
fu_rcuhead | RCU(Read-Copy-Update)链表表头 | |
f_path | struct path类型,里面包含了文件系统挂载点信息vfsmount,同时链接到当前文件对应的目录项dentry | struct path { struct vfsmount *mnt; struct dentry *dentry; } |
f_inode | 文件对象缓存的索引节点信息 | |
f_op | 指向文件操作表struct file_operations | 文件操作表包含读取、写入、打开、释放等文件操作的函数指针 |
f_lock | 自旋锁 | 保护f_ep, f_flags两个标志位 |
f_write_hint | 对文件的写入操作的提示,用于优化写入操作 | WRITE_LIFE_NOT_SET WRITE_LIFE_NONE WRITE_LIFE_SHORT WRITE_LIFE_MEDIUM WRITE_LIFE_LONG WRITE_LIFE_EXTREME u8 i_write_hint; |
f_count | 文件引用计数器,跟踪文件对象使用情况 | 当计数器为0时,可以安全地释放文件对象 |
f_flags | 文件自身的标志位,打开文件后可以获取 | fcntl.h #define O_ACCMODE 00000003 #define O_RDONLY 00000000 #define O_WRONLY 00000001 #define O_RDWR 00000002 …… |
f_mode | 用户期望的文件打开方式,在打开文件时指定 | fs.h FMODE_READ FMODE_WRITE FMODE_LSEEK FMODE_PREAD |
f_pos_lock | 文件位置操作的互斥锁 | 更新文件位置时使用 |
f_pos | 跟踪文件中当前的读写位置(偏移量) | 随着从文件读取或写入数据,该位置将被更新 |
f_owner | 标识当前打开文件所属的进程信息 | struct fown_struct { rwlock_t lock; struct pid *pid; enum pid_type pid_type; kuid_t uid, euid; int signum; }; |
f_cred | 指向与文件相关联的用户凭证信息 | 查看cred.h |
f_ra | 记录文件的预读信息 | struct file_ra_state { pgoff_t start; unsigned int size; unsigned int async_size; unsigned int ra_pages; unsigned int mmap_miss; loff_t prev_pos; }; |
f_version | 版本号 | 当f_pos改变时候,version递增 |
private_data | 私有数据 | 在设备驱动中被广泛应用,大多被指向设备驱动自定义用于描述设备的结构体 |
f_ep | fs/eventpoll.c使用 | |
f_mapping | 文件地址映射对象 | 用于将文件直接映射到内存中,以便快速、有效地访问文件数据。f_mapping结构包含了与文件映射相关的各种信息,例如文件的起始位置、大小、访问权限等 |
f_wb_err | 记录写入错误信息 | |
f_sb_err | 记录syncfs错误信息 |
二、文件对象操作表
由于file对象表示进程打开的文件,所以文件对象操作表f_op主要是关于文件操作,比如:llseek、read、write、flush、fsync等等,以下会详细解读
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 (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *,
unsigned int flags);
int (*iterate) (struct file *, struct dir_context *);
int (*iterate_shared) (struct file *, struct dir_context *);
__poll_t (*poll) (struct file *, struct poll_table_struct *);
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 *);
unsigned long mmap_supported_flags;
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_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 **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(struct file *);
#endif
ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
loff_t, size_t, unsigned int);
loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
loff_t len, unsigned int remap_flags);
int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;
函数 | 涵义 | 使用说明 |
llseek | 移动文件指针 | |
read | 用户读操作时,会调用此函数 | |
write | 会写操作时,会调用此函数 | |
read_iter | 使用迭代器iov_iter读操作 | |
write_iter | 使用iovec迭代iov_iter写操作 | |
iopoll | 当aio想要在HIPRI iocbs上轮询完成情况时调用 | |
iterate | ||
iterate_shared | 用于VFS读取目录信息 | |
poll | 当进程要check当前文件上是否有活动,也就是select(2) 和poll系统调用,触发VFS调用此函数 | |
unlocked_ioctl | ioctl(2)系统调用,触发回调此函数 | |
compat_ioctl | ioctl(2)系统调用,并且32位系统使用64位内核,触发回调此函数 | |
mmap | mmap(2)系统调用,触发回调此函数 | |
open | VFS当创建文件对象后,触发回调此函数 | 比如:可以在此函数中,设置private_data |
flush | 当调用close操作时,flush缓冲区 | |
release | 当前文件最后一个引用关闭时,触发回调此函数 | |
fsync | 用户调用fsync(2)系统调用时,触发回调此函数 | |
fasync | 用户调用fcntl(2)系统调用,并且是异步非阻塞,触发回调此函数 | |
lock | 用户调用fcntl(2)系统调用,请求命令F_GETLK, F_SETLK, and F_SETLKW,触发回调此函数 | |
sendpage | ||
get_unmapped_area | ||
check_flags | ||
flock | 用户调用flock(2)系统调用,回调此函数 | |
splice_write | 由VFS调用,将数据从管道拼接写到文件 | 由系统调用splice(2)触发 |
splice_read | 由VFS调用,将数据从文件拼接读到管道 | 由系统调用splice(2)触发 |
setlease | VFS调用设置或释放租约锁, | |
fallocate | 由VFS调用以预分配块空间或预打洞 | |
show_fdinfo | ||
mmap_capabilities | ||
copy_file_range | copy_file_range(2)系统调用,触发回调此函数 | |
remap_file_range | 由ioctl(2)系统调用触发,回调此函数 | 当需要FICLONERANG、FICLONE和FIDEDUPERANG命令来重新映射文件范围时 |
fadvise | fadvise64()系统调用,触发回调此函数 |
上一篇:Linux文件系统数据结构详解:挂载点mount和vfsmount
参考资料:
小立爱学习:https://blog.csdn.net/weixin_45030965/article/details/133805594
怎么没有讲文件描述符啊,描述符到底怎么来的,这个比较重要