简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
1.前言
本篇目的:Linux内核之最核心数据结构:struct file解析
2.介绍
struct file
是Linux内核中一个非常重要的结构体,它在文件系统中扮演着桥梁的角色,连接用户空间的应用程序和内核的文件操作。每当用户空间进程打开一个文件时,内核就会创建一个struct file
实例来跟踪对该文件的所有操作。struct file
的作用主要体现在以下几个方面:
- 跟踪文件访问模式:
struct file
中的f_mode
字段用来存储文件的用户访问模式,如只读(O_RDONLY)、只写(O_WRONLY)或读写(O_RDWR)。这告诉内核该文件应该以何种方式被访问,以便内核可以进行相应的权限检查和文件状态管理。 - 实现随机访问:通过
f_pos
字段,struct file
记录了当前文件的位置,使得进程可以进行随机读写。每次文件操作后,内核会更新这个位置,以便下一次操作可以从这个位置继续。 - 版本控制:
f_version
字段用于标识文件的版本,这在多线程环境中非常重要,可以确保一个文件的并发读写操作不会因为不同进程的读写而产生数据不一致的问题。 - 存储文件操作:
f_op
字段是一个指向struct file_operations
的指针,这个结构体定义了文件的各个操作函数,如读(read)、写(write)、定位(lseek)等。当用户空间进程请求进行文件操作时,内核会调用这些函数来执行具体的操作。 - 维护文件引用计数:
f_count
字段用于维护文件描述符的使用计数。每当进程打开一个文件时,计数会增加;当文件被关闭时,计数会减少。这个计数对于确保文件在多个进程间正确共享非常重要。 - 进程间通信:
f_owner
字段包含了拥有该文件描述符的进程的PID,这有助于内核确定文件操作的权限,例如,只有拥有者进程才能执行某些特定的文件操作。 - 路径名和Dentry:
f_name
字段通常存储文件路径名,而f_dentry
字段则指向一个struct dentry
,它代表了文件系统中的一个目录项。通过这个目录项,内核可以访问到文件的详细信息,如文件类型、大小、权限等。 - 文件锁和同步:
f_flags
字段包含了文件的各种标志,如是否被锁定(FILE_LOCKED)等。这些标志可以帮助内核管理文件的并发访问,确保数据的一致性和完整性。 - 私有数据:
private_data
字段允许struct file
的实现者存储与特定文件类型相关的私有数据。这为文件操作提供了极大的灵活性,使得内核开发者可以根据不同类型的文件实现特定的行为。
- 总结来说,
struct file
结构体是Linux内核文件系统的一个核心组件,它不仅为用户空间进程提供了一个与文件交互的接口,还内核提供了一种方式来跟踪和管理这些交互。通过struct file
,内核能够高效地处理文件访问、同步和权限控制等复杂任务,确保了文件系统的稳定性和可靠性。
3.代码实例
<1>.struct file结构体
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;
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
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
errseq_t f_wb_err;
}
<2>.struct file结构体每个字段注释
1.f_u:
一个联合体,用于表示文件使用的数据结构。可以根据不同的使用方式选择存储在 fu_llist 中或者 fu_rcuhead 中。
2.fu_llist:
用于将文件链接到文件系统的文件使用链表中。
3.fu_rcuhead:
用于在文件引用计数为零时释放文件资源。
4.f_path:
表示文件的路径信息,包括目录项和 dentry 项。
5.f_inode:
指向文件的 inode 结构体,用于表示文件在文件系统中的详细信息。这是一个缓存值,可以用于快速访问文件的 inode。
6.f_op:
指向文件的操作函数表,包含了文件操作的函数指针。
7.f_lock:
自旋锁,用于保护与文件相关的链接列表和标志位。在非中断上下文中使用。
8.f_write_hint:
用于存储对文件的写入操作的提示,用于优化写入操作。
9.f_count:
原子长整型,表示文件的引用计数。
10.f_flags:
存储文件的标志位,用于表示文件的打开模式和属性。
11.f_mode:
存储文件的打开模式,用于表示文件的访问权限。
12.f_pos_lock:
互斥锁,用于保护文件的位置信息。
13.f_pos:
文件的当前读/写位置。
14.f_owner:
用于存储文件的所有者信息。
15.f_cred:
指向与文件关联的安全凭证信息。
16.f_ra:
与文件相关的读取加速信息。
17.f_version:
文件的版本号。
18.f_security:
与文件相关的安全信息,若配置了安全模块则存在,否则为空。
19.private_data:
用于存储文件的私有数据,由文件操作函数使用。
20.f_ep_links:
用于在 epoll 事件轮询机制中链接所有与此文件相关的 hooks。
21.f_tfile_llink:
用于链接到 tracefs 文件系统的跟踪文件。
22.f_mapping:
23.指向文件的地址空间对象,表示文件的数据存储方式。
24f_wb_err:
文件的写入错误信息。
25. __randomize_layout 和 __attribute__((aligned(4)))
是对结构体布局和对齐的优化选项。
<3>.struct rcu_head结构体定义:用于在文件引用计数为零时释放文件资源。
struct callback_head {
struct callback_head *next;
void (*func)(struct callback_head *head);
} __attribute__((aligned(sizeof(void *))));
#define rcu_head callback_head
定义回调函数
<4>.struct path结构体定义:表示文件的路径信息,包括目录项和 dentry 项。
private/msm-google/include/linux/path.h
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
} __randomize_layout;
struct vfsmount结构体
struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
int mnt_flags;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
ANDROID_KABI_RESERVE(4);
void *data;
} __randomize_layout;
struct dentry结构体
struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock */
seqcount_t d_seq; /* per dentry seqlock */
struct hlist_bl_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
/* Ref lookup also touches following */
struct lockref d_lockref; /* per-dentry lock and refcount */
const struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
unsigned long d_time; /* used by d_revalidate */
void *d_fsdata; /* fs-specific data */
union {
struct list_head d_lru; /* LRU list */
wait_queue_head_t *d_wait; /* in-lookup ones only */
};
struct list_head d_child; /* child of parent list */
struct list_head d_subdirs; /* our children */
/*
* d_alias and d_rcu can share memory
*/
union {
struct hlist_node d_alias; /* inode alias list */
struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
struct rcu_head d_rcu;
} d_u;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
} __randomize_layout;
<5>.const struct 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 (*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 (*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);
int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
u64);
int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t,
u64);
int (*fadvise)(struct file *, loff_t, loff_t, int);
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
ANDROID_KABI_RESERVE(4);
} __randomize_layout;
文件操作的回调函数