010 Linux文件系统数据结构详解:文件对象struct file

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_rcuheadRCU(Read-Copy-Update)链表表头
f_pathstruct path类型,里面包含了文件系统挂载点信息vfsmount,同时链接到当前文件对应的目录项dentrystruct 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_epfs/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_ioctlioctl(2)系统调用,触发回调此函数
compat_ioctlioctl(2)系统调用,并且32位系统使用64位内核,触发回调此函数
mmapmmap(2)系统调用,触发回调此函数
openVFS当创建文件对象后,触发回调此函数比如:可以在此函数中,设置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)触发
setleaseVFS调用设置或释放租约锁,
fallocate由VFS调用以预分配块空间或预打洞
show_fdinfo
mmap_capabilities
copy_file_rangecopy_file_range(2)系统调用,触发回调此函数
remap_file_range由ioctl(2)系统调用触发,回调此函数当需要FICLONERANG、FICLONE和FIDEDUPERANG命令来重新映射文件范围时
fadvisefadvise64()系统调用,触发回调此函数

上一篇:Linux文件系统数据结构详解:挂载点mount和vfsmount

参考资料:

小立爱学习:https://blog.csdn.net/weixin_45030965/article/details/133805594

《010 Linux文件系统数据结构详解:文件对象struct file》有2个想法

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注