Linux VFS(Virtual Filesystem)是 Linux 内核中的一组机制和数据结构,用于统一管理各种不同类型的文件系统和文件操作。它提供了一个抽象的文件系统接口,使得用户空间程序可以通过统一的方式来访问不同的文件系统,而不需要关心底层文件系统的具体实现细节
注册文件系统
以下两个函数允许文件系统开发者将他们实现的文件系统类型集成到 Linux 内核中,以便用户可以使用该文件系统。
// 用于将文件系统类型注册到内核中
extern int register_filesystem(struct file_system_type *);
// 用于从内核中移除已注册的文件系统类型
extern int unregister_filesystem(struct file_system_type *);
file_system_type 文件系统类型
struct file_system_type {
const char *name; // 文件系统类型的名称,以字符串形式表示。 如 “ext2”, “iso9660”, “msdos”
int fs_flags; // 文件系统的标志位,用于指定一些特性或属性,例如是否需要设备、是否支持用户命名空间挂载等。
int (*init_fs_context)(struct fs_context *); // 用于初始化文件系统上下文。
const struct fs_parameter_spec *parameters; // 指向一个文件系统参数规范的指针,用于指定文件系统挂载时的参数。
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *); //指向一个挂载函数的指针,用于挂载文件系统。
void (*kill_sb) (struct super_block *); // 指向一个超级块销毁函数的指针,用于销毁文件系统的超级块。
struct module *owner; // 指向拥有该文件系统类型的内核模块的指针。
struct file_system_type * next; // 指向下一个文件系统类型结构体的指针,用于构建文件系统类型链表。
struct hlist_head fs_supers; // 文件系统类型的超级块列表头,用于管理该类型的文件系统的超级块。
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
struct lock_class_key s_vfs_rename_key;
struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];
struct lock_class_key i_lock_key;
struct lock_class_key i_mutex_key;
struct lock_class_key invalidate_lock_key;
struct lock_class_key i_mutex_dir_key;
};
// fs_flags 可取以下值
#define FS_REQUIRES_DEV 1 // 需要设备才能挂载的文件系统
#define FS_BINARY_MOUNTDATA 2 // 挂载数据是二进制的
#define FS_HAS_SUBTYPE 4 // 具有子类型
#define FS_USERNS_MOUNT 8 /* 可以由用户命名空间根挂载*/
#define FS_DISALLOW_NOTIFY_PERM 16 /* 禁止 fanotify 权限事件*/
#define FS_ALLOW_IDMAP 32 /* 文件系统已更新以处理 vfs idmappings*/
#define FS_THP_SUPPORT 8192 /*透明大页支持*/
#define FS_RENAME_DOES_D_MOVE 32768 /* 在重命名时会处理 d_move() */
fs_context 对象
主要用于文件系统的挂载操作。
// 用于在创建或重新配置超级块时保存参数的文件系统上下文。
struct fs_context {
// 指向文件系统上下文操作的指针
const struct fs_context_operations *ops;
// 用户空间访问互斥锁。
struct mutex uapi_mutex;
// 指向文件系统类型的指针。
struct file_system_type *fs_type;
// 文件系统的上下文。
void *fs_private;
// sget 函数使用的键值。
void *sget_key;
// 根和超级块。
struct dentry *root;
// 此挂载的用户命名空间。
struct user_namespace *user_ns;
// 此挂载的网络命名空间。
struct net *net_ns;
// 挂载者的凭据。
const struct cred *cred;
// 日志缓冲区。
struct p_log log;
// 源名称(例如设备路径)。
const char *source;
// Linux S&M(安全和管理)选项。
void *security;
// 建议的 s_fs_info。
void *s_fs_info;
// 建议的超级块标志(SB_*)。
unsigned int sb_flags;
// 已更改的超级块标志。
unsigned int sb_flags_mask;
// 与 sb->s_iflags 进行 OR 运算。
unsigned int s_iflags;
// 来自文件系统到 LSM 的信息标志。
unsigned int lsm_flags;
// 文件系统上下文目的。
enum fs_context_purpose purpose:8;
// 上下文所处的阶段。
enum fs_context_phase phase:8;
// 是否需要调用 ops->free()。
bool need_free:1;
// 是否进入 &init_user_ns。
bool global:1;
// 是否来自 mount(2)。
bool oldapi:1;
};
fs_context_operations 文件系统上下文操作
// 用于定义文件系统上下文操作的接口
// 每个操作都接受一个指向 struct fs_context 结构的指针作为参数,这是对应的文件系统上下文。
struct fs_context_operations {
// 释放文件系统上下文的资源。
void (*free)(struct fs_context *fc);
// 复制文件系统上下文的内容到另一个上下文。
int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
// 解析文件系统参数。
int (*parse_param)(struct fs_context *fc, struct fs_parameter *param);
// 解析单体式文件系统参数。
int (*parse_monolithic)(struct fs_context *fc, void *data);
// 获取文件系统树。
int (*get_tree)(struct fs_context *fc);
// 重新配置文件系统。
int (*reconfigure)(struct fs_context *fc);
};
super_block 对象
该对象用于存储特定文件系统的信息,通常对应于存放在磁盘特定散区中的文件系统超级块或文件系统控制块。 对应并非基于磁盘的文件系统 (如基于内存的文件系统,比如 sysfs) ,它们会在使用现场创建的超级块并将其保存在内存中
struct super_block {
struct list_head s_list; /* Keep this first 指向所有超级块的链表*/
dev_t s_dev; /* search index; _not_ kdev_t 设备标识符*/
unsigned char s_blocksize_bits; /*以位为单位的块大小*/
unsigned long s_blocksize; /*以字节为单位块的大小*/
loff_t s_maxbytes; /* Max file size */
struct file_system_type *s_type; /*文件系统类型*/
const struct super_operations *s_op; /*超级块方法*/
const struct dquot_operations *dq_op; /*磁盘超限方法*/
const struct quotactl_ops *s_qcop; /*限额控制方法 */
const struct export_operations *s_export_op; /*导出方法*/
unsigned long s_flags; /*挂载标识*/
unsigned long s_iflags; /* internal SB_I_* flags */
unsigned long s_magic; /*文件系统的魔数*/
struct dentry *s_root; /*目录挂载点*/
struct rw_semaphore s_umount; /*卸载信号量*/
int s_count; /*超级块引用计数*/
atomic_t s_active; /*活动引用计数*/
#ifdef CONFIG_SECURITY
void *s_security; /**安全模块/
#endif
const struct xattr_handler **s_xattr; /*扩展的属性操作*/
#ifdef CONFIG_FS_ENCRYPTION
const struct fscrypt_operations *s_cop;
#ifdef __GENKSYMS__
/*
* Android ABI CRC preservation due to commit 391cceee6d43 ("fscrypt:
* stop using keyrings subsystem for fscrypt_master_key") changing this
* type. Size is the same, this is a private field.
*/
struct key *s_master_keys; /* master crypto keys in use */
#else
struct fscrypt_keyring *s_master_keys; /* master crypto keys in use */
#endif
#endif
#ifdef CONFIG_FS_VERITY
const struct fsverity_operations *s_vop;
#endif
#ifdef CONFIG_UNICODE
struct unicode_map *s_encoding;
__u16 s_encoding_flags;
#endif
struct hlist_bl_head s_roots; /* alternate root dentries for NFS */
struct list_head s_mounts; /* list of mounts; _not_ for fs use */
struct block_device *s_bdev; /* 相关的块设备*/
struct backing_dev_info *s_bdi;
struct mtd_info *s_mtd; /*存储磁盘信息*/
struct hlist_node s_instances; /*该类型文件系统*/
unsigned int s_quota_types; /* Bitmask of supported quota types */
struct quota_info s_dquot; /* Diskquota specific options * 限额相关选项/
struct sb_writers s_writers;
/*
* Keep s_fs_info, s_time_gran, s_fsnotify_mask, and
* s_fsnotify_marks together for cache efficiency. They are frequently
* accessed and rarely modified.
*/
void *s_fs_info; /* Filesystem private info */
/* Granularity of c/m/atime in ns (cannot be worse than a second) */
u32 s_time_gran; /*时间戳粒度*/
/* Time limits for c/m/atime in seconds */
time64_t s_time_min;
time64_t s_time_max;
#ifdef CONFIG_FSNOTIFY
__u32 s_fsnotify_mask;
struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
#endif
char s_id[32]; /* Informational name */
uuid_t s_uuid; /* UUID */
unsigned int s_max_links;
fmode_t s_mode;
/*
* The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned.
*/
struct mutex s_vfs_rename_mutex; /* Kludge */
/*
* Filesystem subtype. If non-empty the filesystem type field
* in /proc/mounts will be "type.subtype"
*/
const char *s_subtype; /*子类型名称*/
const struct dentry_operations *s_d_op; /* default d_op for dentries */
/*
* Saved pool identifier for cleancache (-1 means none)
*/
int cleancache_poolid;
struct shrinker s_shrink; /* per-sb shrinker handle */
/* Number of inodes with nlink == 0 but still referenced */
atomic_long_t s_remove_count;
/*
* Number of inode/mount/sb objects that are being watched, note that
* inodes objects are currently double-accounted.
*/
atomic_long_t s_fsnotify_connectors;
/* Being remounted read-only */
int s_readonly_remount;
/* per-sb errseq_t for reporting writeback errors via syncfs */
errseq_t s_wb_err;
/* AIO completions deferred from interrupt context */
struct workqueue_struct *s_dio_done_wq;
struct hlist_head s_pins;
/*
* Owning user namespace and default context in which to
* interpret filesystem uids, gids, quotas, device nodes,
* xattrs and security labels.
*/
struct user_namespace *s_user_ns;
/*
* The list_lru structure is essentially just a pointer to a table
* of per-node lru lists, each of which has its own spinlock.
* There is no need to put them into separate cachelines.
*/
struct list_lru s_dentry_lru;
struct list_lru s_inode_lru;
struct rcu_head rcu;
struct work_struct destroy_work;
struct mutex s_sync_lock; /* sync serialisation lock */
/*
* Indicates how deep in a filesystem stack this SB is
*/
int s_stack_depth;
/* s_inode_list_lock protects s_inodes */
spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp;
struct list_head s_inodes; /* all inodes inodes 链表*/
spinlock_t s_inode_wblist_lock;
struct list_head s_inodes_wb; /* writeback inodes */
};
超级块操作
struct super_operations {
// 在给定的超级块下创建和初始化一个新的索引节点对象
struct inode *(*alloc_inode)(struct super_block *sb);
// 用于释放给定的索引节点,但不释放 inode 结构体本身的内存
void (*destroy_inode)(struct inode *);
// 完全释放一个 inode,包括释放 inode 结构体本身的内存
void (*free_inode)(struct inode *);
// 在索引节点脏(被修改)时会调用此函数。日志文件系统(如 ext3 和 ext4)执行该函数进行日志更新
void (*dirty_inode) (struct inode *, int flags);
// 用于将给定的索引节点写入磁盘,
int (*write_inode) (struct inode *, struct writeback_control *wbc);
// drop_inode 函数用于减少 inode 结构体的引用计数
int (*drop_inode) (struct inode *);
// evict_inode 函数在文件系统卸载或者 inode 不再被缓存时调用,以释放 inode 的资源并将其从内存中移除。
void (*evict_inode) (struct inode *);
// 释放超级块的资源
void (*put_super) (struct super_block *);
// 同步文件系统的所有未同步的数据
int (*sync_fs)(struct super_block *sb, int wait);
// 冻结超级块,防止写操作对文件系统进行修改。
int (*freeze_super) (struct super_block *);
// 冻结文件系统,防止写操作对文件系统进行修改
int (*freeze_fs) (struct super_block *);
// 解冻超级块,允许写操作对文件系统进行修改。
int (*thaw_super) (struct super_block *);
// 解冻文件系统,允许写操作对文件系统进行修改
int (*unfreeze_fs) (struct super_block *);
// 获取文件系统的统计信息
int (*statfs) (struct dentry *, struct kstatfs *);
// 重新挂载文件系统,可修改挂载选项
int (*remount_fs) (struct super_block *, int *, char *);
// 开始卸载文件系统的操作
void (*umount_begin) (struct super_block *);
// 显示文件系统的挂载选项
int (*show_options)(struct seq_file *, struct dentry *);
// 显示文件系统的设备名称
int (*show_devname)(struct seq_file *, struct dentry *);
// 显示文件系统的路径
int (*show_path)(struct seq_file *, struct dentry *);
// 显示文件系统的统计信息
int (*show_stats)(struct seq_file *, struct dentry *);
#ifdef CONFIG_QUOTA
// 读取磁盘配额信息
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
// 写入磁盘配额信息
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
// 获取与 inode 相关的磁盘配额结构体指针
struct dquot **(*get_dquots)(struct inode *);
#endif
// 获取缓存对象的数量
long (*nr_cached_objects)(struct super_block *,
struct shrink_control *);
// 释放缓存对象
long (*free_cached_objects)(struct super_block *,
struct shrink_control *);
};
inode 对象
索引节点对象包含了内核在操作文件或者目录时需要的全部信息 。这些信息可以从磁盘索引节点直接读入。如果一个文件系统没有索引节点,那么,不管这些相关信息在磁盘上是怎么存放的,文件系统都必须从中提取这些信息。没有索引节点的文件系统通常将文件的描述信息作为文件的一部分来存放。这些文件系统与 Unix 风格的文件系统不同,没有将数据和控制信息分开存放。有些现代文件系统使用数据库来存储文件的数据。不管哪种情况,采用哪种方式,索引节点对象必须在内存中创建,以便文件系统使用 。
索引节点对象 由 inode 结构体表示
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
umode_t i_mode; // 文件的访问权限和类型。
unsigned short i_opflags; // inode 操作标志。
kuid_t i_uid; // 文件所有者的用户 ID。
kgid_t i_gid; // 文件所属组的组 ID。
unsigned int i_flags; // inode 的标志位
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl; // 指向文件的 ACL(访问控制列表)的指针。
struct posix_acl *i_default_acl; // 指向文件的默认 ACL 的指针。
#endif
const struct inode_operations *i_op; // 指向 inode 操作函数表的指针。
struct super_block *i_sb; // 指向超级块(super_block)的指针。
struct address_space *i_mapping; // 指向文件的地址空间描述符的指针。
#ifdef CONFIG_SECURITY
void *i_security; // 用于安全性相关的指针。
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino; // inode 号。
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink; // 硬链接数。
unsigned int __i_nlink;
};
dev_t i_rdev; // 特殊文件的设备号。
loff_t i_size; // 文件大小。
struct timespec64 i_atime; // 文件的访问时间。
struct timespec64 i_mtime; // 文件的修改时间.
struct timespec64 i_ctime; // 文件的状态修改时间(修改inode)。
spinlock_t i_lock; /* inode 自旋锁*/
unsigned short i_bytes; // 文件的字节数
u8 i_blkbits; // 文件系统块大小的位数。
u8 i_write_hint; // 写入操作的提示。
blkcnt_t i_blocks; // 文件的块数。
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state; // inode 的状态标志。
struct rw_semaphore i_rwsem; // 读写信号量。
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when; // inode 第一次变脏的时间。
struct hlist_node i_hash; // 用于哈希表的节点。
struct list_head i_io_list; /* backing dev IO list 用于后端设备 I/O 链表*/
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb 关联的 cgroup writeback 结构体。 */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list inode LRU 链表。*/
struct list_head i_sb_list; // 用于超级块链表。
struct list_head i_wb_list; /* backing dev writeback list 用于后端设备写回链表。*/
union {
struct hlist_head i_dentry; // dentry 哈希表
struct rcu_head i_rcu;
};
atomic64_t i_version; // 用于 futex 的版本
atomic64_t i_sequence; /* see futex 用于 futex 的序列号*/
atomic_t i_count; // 引用计数和 I/O 计数。
atomic_t i_dio_count;
atomic_t i_writecount;
#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
atomic_t i_readcount; /* struct files open RO */
#endif
union {
const struct file_operations *i_fop; /* 指向文件操作函数表的指针。 former ->i_op->default_file_ops */
void (*free_inode)(struct inode *);
};
struct file_lock_context *i_flctx; // 文件锁上下文
struct address_space i_data; // 文件的地址空间描述符
struct list_head i_devices; // 设备列表
union { // 特殊文件类型的具体信息
struct pipe_inode_info *i_pipe;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
__u32 i_generation; // inode 的生成号
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* 用于文件系统通知的相关信息 all events this inode cares about */
struct fsnotify_mark_connector __rcu *i_fsnotify_marks;
#endif
#ifdef CONFIG_FS_ENCRYPTION
struct fscrypt_info *i_crypt_info; // 加密信息。
#endif
#ifdef CONFIG_FS_VERITY
struct fsverity_info *i_verity_info; // 验证信息。
#endif
void *i_private; /* 文件系统或设备私有指针 fs or device private pointer */
};
inode 操作
struct inode_operations {
// 查找操作,用于在给定目录下查找指定文件名的目标 inode。
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
// 获取符号链接目标的操作,用于获取符号链接的目标路径。
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
// 权限检查操作,用于检查用户对 inode 所代表的文件的访问权限。
int (*permission) (struct user_namespace *, struct inode *, int);
// 获取 ACL(访问控制列表)的操作,用于获取 inode 的 ACL 信息。
struct posix_acl * (*get_acl)(struct inode *, int, bool);
// 读取符号链接内容的操作,用于读取符号链接文件的内容。
int (*readlink) (struct dentry *, char __user *,int);
// 用于创建新文件。
int (*create) (struct user_namespace *, struct inode *,struct dentry *,
umode_t, bool);
// 用于创建硬链接。
int (*link) (struct dentry *,struct inode *,struct dentry *);
// 用于删除文件或硬链接。
int (*unlink) (struct inode *,struct dentry *);
// 用于创建符号链接。
int (*symlink) (struct user_namespace *, struct inode *,struct dentry *,
const char *);
// 用于创建新目录。
int (*mkdir) (struct user_namespace *, struct inode *,struct dentry *,
umode_t);
// 用于删除目录
int (*rmdir) (struct inode *,struct dentry *);
// 用于创建新设备节点。创建特殊文件(设备文件,命名管道或套接字)
int (*mknod) (struct user_namespace *, struct inode *,struct dentry *,
umode_t,dev_t);
// 用于重命名文件或目录
int (*rename) (struct user_namespace *, struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
// 用于设置文件的属性
int (*setattr) (struct user_namespace *, struct dentry *,
struct iattr *);
// 用于获取文件的属性
int (*getattr) (struct user_namespace *, const struct path *,
struct kstat *, u32, unsigned int);
// 用于列出文件的扩展属性
ssize_t (*listxattr) (struct dentry *, char *, size_t);
// 用于映射文件的区域
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
// 用于更新文件的时间戳。
int (*update_time)(struct inode *, struct timespec64 *, int);
// 用于原子性地打开文件
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode);
// 用于创建临时文件
int (*tmpfile) (struct user_namespace *, struct inode *,
struct dentry *, umode_t);
// 用于设置 inode 的 ACL 信息
int (*set_acl)(struct user_namespace *, struct inode *,
struct posix_acl *, int);
// 用于设置文件的属性
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
// 用于获取文件的属性
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
};
dentry 对象
VFS 把目录当作文件对待,所以在路径 /bin/vi 中 ,bin 和vi都属于文件 — bin是特殊的目录文件 而 vi 是普通的文件,路径中的每一个组成部分都是有一个索引节点对象 表示的。 虽然它们可以统一有索引节点表示,但是 VFS经常需要执行目录相关操作,比如路径名查找等。路径名查找需要解析路径中的每一个组成部分,不但要确保它有效,而且还需要再进一步寻找路径中的下一个部分。
为了方法查找操作,VFS引入了目录项的概念。每一个 dentry 代表路径中的一个特定部分。对一前一个例子来说 ,/ ,bin,和 vi 都属于目录项对象 ,前两个是目录,最后一个是普通文件 。 必须明确一点 ,在路径中 (包括普通文件在内) ,每一个部分都是目录项对象 。解析一个路径并遍历其分量绝非是简单的演练,它是耗时的,常规的字符串比较过程 ,执行耗时,代码繁琐。目录项对象的引入使得过程更加简单。
目录项也可以包括安装点 。在路径 /mnt/cdrom/foo 中,构成元素 / ,mnt ,cdrom 和 foo都属于目录项对象 。VFS在执行目录操作时(如果需要的话) 会在现场创建目录项对象 。
struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock 目录项的标志位,由 d_lock 保护。*/
seqcount_spinlock_t d_seq; /* per dentry seqlock 用于 RCU 查找的序列计数锁*/
struct hlist_bl_node d_hash; /* lookup hash list 用于查找哈希表的节点*/
struct dentry *d_parent; /* parent directory 父目录的指针*/
struct qstr d_name; // 目录项的名称。
// 指向该目录项对应的 inode 结构体的指针。如果该目录项表示的是一个负目录项(即不存在的目录项),则此指针为空。
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; /*指向该目录项所属的超级块(super_block)的指针。 The root of the dentry tree */
unsigned long d_time; /*用于目录项重新验证的时间戳 used by d_revalidate */
void *d_fsdata; /*用于存储文件系统特定数据的指针。 fs-specific data */
union { //LRU(最近最少使用)列表
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 别名列表。inode alias list */
struct hlist_bl_node d_in_lookup_hash; /*仅在查找过程中使用的哈希列表。 only for in-lookup ones */
struct rcu_head d_rcu; // RCU 头
} d_u;
} ;
dentry 操作
struct dentry_operations {
// 用于重新验证目录项是否仍然有效。如果目录项对应的文件或目录状态发生了变化,例如文件被修改或删除,就需要重新验证目录项的有效性。该函数返回一个整数值,表示验证结果。
int (*d_revalidate)(struct dentry *, unsigned int);
// 类似于 d_revalidate,但是用于执行弱验证。弱验证可能不需要进行完整的文件系统操作,适用于一些简单的情况。
int (*d_weak_revalidate)(struct dentry *, unsigned int);
// 计算目录项的哈希值。通常用于加速目录项的查找
int (*d_hash)(const struct dentry *, struct qstr *);
// 比较两个目录项的名称是否相同。通常用于目录项的查找
int (*d_compare)(const struct dentry *,
unsigned int, const char *, const struct qstr *);
// 删除目录项。当目录项被释放时,该函数会被调用
int (*d_delete)(const struct dentry *);
// 用于在创建新的目录项时执行一些初始化操作。
int (*d_init)(struct dentry *);
// 当目录项不再被引用时,该函数会被调用以释放相关资源。
void (*d_release)(struct dentry *);
// 对目录项进行修剪操作。用于删除不再需要的目录项。
void (*d_prune)(struct dentry *);
// 关联目录项与其对应的 inode。在目录项被释放时,用于释放 inode 的相关资源。
void (*d_iput)(struct dentry *, struct inode *);
// 获取目录项的路径名。将目录项的路径名写入指定的字符缓冲区中。
char *(*d_dname)(struct dentry *, char *, int);
// 自动挂载函数。用于在自动挂载过程中执行特定操作。
struct vfsmount *(*d_automount)(struct path *);
// 用于检查或更改目录项的权限
int (*d_manage)(const struct path *, bool);
// 获取目录项的真实目录项。通常用于处理符号链接。
struct dentry *(*d_real)(struct dentry *, const struct inode *);
// 获取目录项的规范路径
void (*d_canonical_path)(const struct path *, struct path *);
} ;
file 对象
文件对象是已打开的文件在内存中的表示,该对象(不是物理文件) 由相应的 open() 系统调用创建,由 close() 系统调用撤销。所有这些文件相关的调用实际上都是文件操作表中定义的方法。因为多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。文件对象仅仅在进程观点上代表已打开文件,它反过来执行目录项对象(反过来执行索引节点),其实只有目录项对象才表示已打开的实际文件 。虽然一个文件对应的文件对象不是唯一的,但对应的索引节点和目录项对象是唯一的 。
struct file {
union { // 用于将文件结构链接到内核的各种列表或 RCU 机制中。
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path; // 包含了文件的路径信息,如文件所在的挂载点和目录项。
struct inode *f_inode; /*指向文件对应的 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; // 文件的拥有者信息,包括进程 ID 和用户 ID。
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 */
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
} __randomize_layout
file 操作
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 *); //使用分散/聚集 I/O 操作将数据读入缓冲区
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); // 使用分散/聚集 I/O 操作将数据从缓冲区写入。
int (*iopoll)(struct kiocb *kiocb, bool spin); // 执行异步 I/O 轮询。
int (*iterate) (struct file *, struct dir_context *); // 在文件中遍历目录条目。
int (*iterate_shared) (struct file *, struct dir_context *); // 类似于 iterate,但用于共享文件系统。
// 对文件描述符进行事件轮询
__poll_t (*poll) (struct file *, struct poll_table_struct *);
// 执行特定于设备的输入/输出控制操作。
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
// 类似于 unlocked_ioctl,但与旧接口兼容。
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
// 将文件或设备映射到内存中
int (*mmap) (struct file *, struct vm_area_struct *);
// 支持的 mmap 操作标志。
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);
};