vfs文件系统注册 快速了解虚拟文件系统

vfs文件系统注册 快速了解虚拟文件系统(1)

前言

为什么 Linux 内核的文件系统类型那么多,都能挂载上呢?为什么系统里可以直接 mount 其他文件系统呢?甚至能把 windows 下的文件夹挂载到 windows 上,为什么 Linux 的虚拟文件系统这么强大?这得益于它的数据结构设计得十分精妙。好像听过,Linux 有什么解决不了的?加一层。

vfs文件系统注册 快速了解虚拟文件系统(2)

VFS 是什么

虚拟文件系统,简称 VFS(Virtual Filesystem),是一个内核软件层。

VFS 的作用

概括地讲,VFS 有两个作用:

  1. 处理与 Unix 标准文件系统相关的所有系统调用
  2. 为各种文件系统提供一个通用的接口
VFS 支持的文件系统类型

以下列出以下常见的文件系统类型,本文暂时不对其进行详细分析。

  1. 磁盘文件系统ext2,ext3,···
  2. 网络文件系统类型nfs,smbfs,···
  3. 特殊文件系统tmpfs,ramfs,···
  4. 伪文件系统procfs,sysfs,···
VFS 的设计思想

VFS 设计的初衷就是要支持所有的文件系统,所以它的设计思想其实就是以面向对象的方式,设计一个通用的文件模型,出于效率考虑,VFS 还是 C 语言写的。在通用文件系统模型中,每个目录也被当作一个文件,可以包含若干文件和其他的子目录。因此,Linux 有一句经典的话:一切皆文件。

关键数据结构介绍

Linux VFS 抽象出 4 种类型的数据结构,实现将不同类型的文件系统挂载到目录结构中。

超级块对象

对于磁盘类文件系统,超级块是存放在磁盘上的文件系统控制块,里面存放已安装文件系统的有关信息,换句话说,一个超级块描述了一个具体的文件系统信息,里面的信息十分重要,也叫元数据,与普通的文件数据相比,元数据丢失会损坏整个文件系统,导致无法挂载之类的问题。当然,不仅超级块,inode上也有很多元数据。

struct super_block { struct list_head s_list; // 超级快链表指针 dev_t s_dev; // 设备表示符 unsigned char s_blocksize_bits; //以位为单位的块的大小 unsigned long s_blocksize; //以字节为单位的块大小 loff_t s_maxbytes; //文件大小的上限 struct file_system_type *s_type; //指向文件系统的file_system_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_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; struct list_head s_inodes; //把所有索引对象链接在一起,存放的是头结点 struct hlist_bl_head s_anon; //匿名目录项 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;//限额相关选项 struct sb_writers s_writers; char s_id[32]; /* Informational name */ u8 s_uuid[16]; /* UUID */ void *s_fs_info; /* Filesystem private info */ unsigned int s_max_links; fmode_t s_mode; u32 s_time_gran; struct mutex s_vfs_rename_mutex; /* Kludge */ char *s_subtype; char __rcu *s_options; const struct dentry_operations *s_d_op; /* default d_op for dentries */ int cleancache_poolid; struct shrinker s_shrink; /* per-sb shrinker handle */ atomic_long_t s_remove_count; int s_readonly_remount; struct workqueue_struct *s_dio_done_wq; struct hlist_head s_pins; struct list_lru s_dentry_lru ____cacheline_aligned_in_smp; struct list_lru s_inode_lru ____cacheline_aligned_in_smp; struct rcu_head rcu; int s_stack_depth; };

索引节点对象(inode)

索引节点存放关于具体文件的一般信息。对于磁盘类文件系统,索引节点也是存放在磁盘上的文件控制块。每个索引节点都有一个索引节点号,这个节点号唯一地标识了文件系统中的文件。

struct inode { umode_t i_mode; //访问权限控制 unsigned short i_opflags; kuid_t i_uid; //使用者的id kgid_t i_gid; //使用组id unsigned int i_flags; //文件系统标志 #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif const struct inode_operations *i_op; //指向索引结点操作结构体的指针 struct super_block *i_sb; //指向inode所属文件系统的超级块的指针 struct address_space *i_mapping; //相关的地址映射 #ifdef CONFIG_SECURITY void *i_security; //安全模块 #endif unsigned long i_ino; //索引结点号。通过ls -i命令可以查看文件的索引节点号 union { const unsigned int i_nlink; //硬链接数 unsigned int __i_nlink; }; dev_t i_rdev; //实际设备标识符号 loff_t i_size; //以字节为单位 struct timespec i_atime; //最后访问时间 struct timespec i_mtime; //最后修改时间 struct timespec i_ctime; //最后改变时间 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; //使用的字节数 unsigned int i_blkbits; 以位为单位的块大小 blkcnt_t i_blocks; //文件的块数 #ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount; #endif unsigned long i_state; //状态标志 struct mutex i_mutex; unsigned long dirtied_when; //首次修改时间 unsigned long dirtied_time_when; struct hlist_node i_hash; //散列表 struct list_head i_wb_list; /* backing dev IO list */ struct list_head i_lru; /* inode LRU list */ struct list_head i_sb_list; //链接一个文件系统中所有inode的链表 union { struct hlist_head i_dentry; //目录项链表 struct rcu_head i_rcu; }; u64 i_version; //版本号 atomic_t i_count; //引用计数 atomic_t i_dio_count; atomic_t i_writecount; //写者计数 #ifdef CONFIG_IMA atomic_t i_readcount; /* struct files open RO */ #endif const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock_context *i_flctx; struct address_space i_data; //设备地址映射 struct list_head i_devices; //块设备链表 union { struct pipe_inode_info *i_pipe; //管道信息 struct block_device *i_bdev; //块设备 struct cdev *i_cdev; //字符设备 }; __u32 i_generation; //索引节点版本号 #ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; /* all events this inode cares about */ struct hlist_head i_fsnotify_marks; #endif void *i_private; /* fs or device private pointer */ };

目录项对象(dentry)

存放 dentry 与对应文件链接的有关信息,每个 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 */ struct list_head d_lru; /* LRU list */ 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 rcu_head d_rcu; } d_u; };

文件对象(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; 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 list_head f_ep_links; struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; //页缓存映射 } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ struct file_handle { __u32 handle_bytes; int handle_type; /* file identifier */ unsigned char f_handle[0]; };

数据结构组织关系图

vfs文件系统注册 快速了解虚拟文件系统(3)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页