1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Linux文件系统二(虚拟文件系统VFS实现原理)

Linux文件系统二(虚拟文件系统VFS实现原理)

时间:2022-05-01 02:27:19

相关推荐

Linux文件系统二(虚拟文件系统VFS实现原理)

创作人QQ:851301776,邮箱:lfr890207@

欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点!

个人座右铭:

1.没有横空出世,只要厚积一定发。

2.你可以学历不高,你可以不上学,但你不能不学习

一、文件系统概述

在Linux操作系统中,一切皆是文件,除了通常所说狭义的文件(文本文件和二进制文件)以外,目录、套接字、设备及管道等都是文件。

文件系统在不同的上下文中有不同的含义。在存储设备缓存文件的方法数据结构和访问方法。按照某种文件系统类型格式化的一块存储介质,内核中负责管理和存储文件的模块,即文件系统,Linux文件系统的架构,分为用户空间、内核空间、硬件3个层面。

1、用户空间

应用程序可以直接使用内核提供的系统调用访问文件:

(1)一个存储设备上的文件系统,只有挂载到内存中目录树的某个目录下,进程才能访问这个文件系统。

(2)系统调用umount用来卸载某个目录下挂载的文件系统。可以执行命令“umount dir”来卸载文件系统,umount命令调用系统调用umount。

备注:

执行命令:mount -t fstype divice dir, 把文件系统挂载到某个目录下,卸载某个目录挂载的执行命令:umount dir。 然后可以执行其他系统调用:open/close/read/write/lseek/fsync/fdatasync.

应用程序可以使用glibc库封装标准I/o流函数访问文件,标准I/o流提供缓冲区,目的尽可能减少调用read/write次数,提高性能。标准I/O流函数:fopen/fclose/fread/fwrite(fflush)/flseek

2、硬件层面

外部存储设备分为块设备、闪存和NVDIMM(非易失性内存)设备3类。块设备主要有2种类型:机械硬盘和闪存类块设备。

机械硬件读写单位为扇区,访问首先沿着半径方向移动磁头寻找磁道,然后转动盘片找到扇区。

闪存作为存储设备,里面的控制器运行固化驱动程序,驱动程序的功能是内存转换层,把闪存转换为块设备,对外表现为块设备。Solid state drives,SSD。手机/平板嵌入式存储卡eMMC(embedded multi meida card)/通用闪存存储UFS(Universal flash storage)。

3、内核空间

在内核的目录fs下可以看到,内核支持多种文件系统类型。为了对用户程序提供统一的文件操作系统接口,为了使不同的文件系统实现能够共存,内核实现一个抽象层,称为虚拟文件系统(Virtual File System VFS),也称为虚拟文件系统切换(Virtual Filesystem Switch,VFS)。

文件系统分为:块设备文件系统(存储设备十二机械硬盘和SSD等块,EXT2/3/4)、闪存文件系统存储设备Nor,NAND闪存、内存文件系统(文件在内存中)、伪文件系统(假的文件系统)。

二、虚拟文件系统数据结构

虽然不同文件系统类型的物理结构不同,但是虚拟文件系统定义一套统一的数据结构。超级块、索引节点、目录项。

1、超级块

文件系统的第一块是超级块,用来描述文件系统的总体信息。当我们把文件系统挂载到内存中的目录树的一个目录下时,就会读取文件系统的超级块,在内存中创建超级块的副本,结构体super_block内核源码,主要成员如下:

超级块操作系统集合的数据结构时:结构体super_operations,主要成员如下:

2、挂载描述符

一个文件系统,只有挂载到内存中目录树的一个目录下,进程才能访问这个文件系统。每次挂载文件系统,虚拟文件系统就会创建一个挂载描述符:mount 结构体。挂载描述符用来描述文件系统的一个挂载实类,同一个存储设备上的文件系统可以多次挂载,每次挂载到不同的目录下。

结构体mount挂载描述符的主要成员如下:

3、文件系统类型

因为每种文件系统类型的超级块的格式不同,所以每种文件系统需要向虚拟文件系统注册文件系统类型file_system_type.并且实现mount方法用来读取和解析超级块。内核源码如下:

struct file_system_type {

const char *name; // 文件系统类型的名称

int fs_flags;

#define FS_REQUIRES_DEV 1

#define FS_BINARY_MOUNTDATA 2

#define FS_HAS_SUBTYPE 4

#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */

#define FS_RENAME_DOES_D_MOVE 32768 /* FS will ha

ndle d_move() during rename() internally. */

// 用来在挂载文件系统的时候读取并且解析超有块

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 i_mutex_dir_key;

};

4、索引节点

在文件系统中,每个文件对应一个索引节点,索引节点描述两类信息:

(1)文件的属性,也称为元数据(metadata)。

(2)文件数据的存储位置,每个索引节点有一个唯一的编号。当内核访问存储设备上的一个文件时,会在内存中创建索引节点的一个副本,内核结构体inode源码如下:

struct inode {

umode_t i_mode; // 文件类型和访问权限

unsigned short i_opflags;

kuid_ti_uid; // 创建文件的用户的标识符

kgid_ti_gid; // 创建文件的用户所属的组标识符

unsigned inti_flags;

#ifdef CONFIG_FS_POSIX_ACLstruct posix_acl *i_acl;

struct posix_acl *i_default_acl;

#endif

const struct inode_operations *i_op;

struct super_block *i_sb; // 指向文件所属的文件系统的超级块

struct address_space *i_mapping; // 指向文件的地址空间

#ifdef CONFIG_SECURITY

void*i_security;

#endif

/* 索引节点编号 */

unsigned longi_ino;

/*

* Filesystems may only read i_nlink directly. They shall u

se 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_ti_rdev;// 设备号

loff_ti_size; // 文件长度

struct timespec i_atime; // 上一次访问文件的时间

struct timespeci_mtime; // 上一次修改文件数据的时间

struct timespec i_ctime; // 上一次修改文件索引节点的赶时间

spinlock_ti_lock; /* i_blocks, i_bytes, maybe i_size */

unsigned shorti_bytes; // 文件长度除以块长度的余数

unsigned inti_blkbits; // 块长度以 2 为底的对数,块长度是 2 的 i_blkbits 次幂

blkcnt_ti_blocks; // 文件的块数

#ifdef __NEED_I_SIZE_ORDERED

seqcount_ti_size_seqcount;

#endif

/* Misc */

unsigned longi_state;

struct rw_semaphore i_rwsem;unsigned long

dirtied_when; /* jiffies of first dirtying*/

unsigned longdirtied_time_when;

struct hlist_node i_hash;

struct list_head i_io_list; /* backing dev IO list */

#ifdef CONFIG_CGROUP_WRITEBACK

struct bdi_writeback *i_wb;

/* the associated cgroup wb */

/* foreign inode detection, see wbc_detach_inode() */

inti_wb_frn_winner;

u16i_wb_frn_avg_time;

u16i_wb_frn_history;

#endif

struct list_head i_lru; /* inode LRU list */

struct list_head i_sb_list;

struct list_head i_wb_list; /* backing dev writeback list*/

union {

struct hlist_head i_dentry;

struct rcu_head i_rcu;

};

u64i_version;

atomic_ti_count;

atomic_ti_dio_count;

atomic_ti_writecount;

#ifdef CONFIG_IMA

atomic_ti_readcount; /* struct files open RO */

#endif

const struct file_operationsi_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; // 指向字符设备

char*i_link;

unsignedi_dir_seq;

};

__u32i_generation;

#ifdef CONFIG_FSNOTIFY

__u32i_fsnotify_mask; /* all events this inode caresabout */

struct fsnotify_mark_connector __rcu *i_fsnotify_marks;

#endif

#if IS_ENABLED(CONFIG_FS_ENCRYPTION)

struct fscrypt_info *i_crypt_info;

#endif

voidi_private; /fs or device private pointer */

};

5、目录项

文件系统把目录当做文件,这种文件的数据是由目录项结构组成的,每个目录项存储一个子目录或文件的名称以及对应的索引节点号。当内核访问存储设备上的一个目录项时,会在内核中创建目录项的一个副本,结构体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; /* 用来把目录项加入散列表 */

struct dentryd_parent; /指向父目录 */

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_blockd_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_td_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;

};

6、文件打开实例及打开文件表

当进程打开一个文件的时候,虚拟文件系统就会创建一个打开实例:file结构体

struct file {

union {

struct llist_node fu_llist;

struct rcu_head fu_rcuhead;

} f_u;

/*struct path {

struct vfsmount *mnt; // 指向文件所属文件系统的挂载描述符的成员 mnt

struct dentry *dentry; // 文件对应的目录项

};*/

struct path f_path; // 存储文件在目录树中的位置

struct inodef_inode; /指向文件的索引节点 */

// 指向文件操作命令

const struct file_operations *f_op;

/** Protects f_ep_links, f_flags.* Must not be taken from IRQ context.*/

spinlock_tf_lock;

atomic_long_tf_count;

unsigned intf_flags;

fmode_tf_mode; // 访问模式

struct mutexf_pos_lock;

loff_tf_pos; // 文件偏移,进程当前正在访问的位置

struct fown_struct f_owner;

const struct cred *f_cred;

struct file_ra_state f_ra;

u64f_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 */

文件系统信息结构主要成员如下:

打开文件表的数据结构如下:

三、注册文件系统类型

因为每种文件系统的超级块的格式不同,所以每种文件系统需要向虚拟文件系统注册文件类型:file_system_type,实现mount方法来读取和解析超级块,函数register_filesystem来注册文件系统类型:

管理员可以执行命令:cat /proc/filesystems--查看已经注册的文件系统类型。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。