创作人QQ:851301776,邮箱:lfr890207@163.com
        欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点!

个人座右铭:
         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_t        i_uid; // 创建文件的用户的标识符

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

unsigned int        i_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 long        i_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_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; // 块长度以 2 为底的对数,块长度是 2 的 i_blkbits 次幂

blkcnt_t        i_blocks; // 文件的块数

#ifdef __NEED_I_SIZE_ORDERED

seqcount_t        i_size_seqcount;

#endif

/* Misc */

unsigned long        i_state;

struct rw_semaphore i_rwsem;unsigned long

dirtied_when; /* jiffies of first dirtying*/

unsigned long        dirtied_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() */

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

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;

};

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

char        *i_link;

unsigned        i_dir_seq;

};

__u32        i_generation;

#ifdef CONFIG_FSNOTIFY

__u32        i_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

void        i_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 dentry d_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_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;

};

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 inode        f_inode; / 指向文件的索引节点 */

// 指向文件操作命令

const struct file_operations *f_op;

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

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

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

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

三、注册文件系统类型

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

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

Linux文件系统二(虚拟文件系统VFS实现原理)相关推荐

  1. Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)

    目录 一.概述 1. 硬盘驱动 2. 通用块设备层 General Block Device Layer 3. 文件系统 4. 虚拟文件系统(VFS) 二.存储介质 闪存(Flash Memory) ...

  2. 深入linux内核架构--虚拟文件系统VFS

    [推荐阅读] Linux内核源码分析--内核启动之zImage自解压过程 你应该知道的Linux内核基础及内核编译 深入理解LINUX内核堆栈 [零声教育]vico老师教你怎么学习Linux内核 值得 ...

  3. linux文件系统dentry_Linux 文件系统(一)---虚拟文件系统VFS----超级块、inode、dentry、file...

    一: 什么是文件系统,详见:http://zh.wikipedia.org/zh/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F 其实一句话就是管理这块文件的机制(组织方式, ...

  4. linux内核之虚拟文件系统

    一.虚拟文件系统概述 虚拟文件系统VFS(也成虚拟文件交换)作为内核子系统,为用户空间程序提供了文件和文件系统相关的统一接口.通过VFS,应用程序可以使用相同接口完成不同介质上不同文件系统的数据读写操 ...

  5. linux 文件系统_Linux 虚拟文件系统

    虚拟文件系统 为了支持各种本机文件系统,且同时允许访问其他操作系统的文件,Linux 内核在用户进程与实际文件系统实现之间引入了一个抽象层,该层称为虚拟文件系统.它的任务并不简单,一方面它要提供一套管 ...

  6. java 虚拟文件系统_虚拟文件系统VFS

    Maven引用坐标: org.tinygroup vfs 0.0.12 一开始,本人抱着对Apache的绝对信任,选择了Apache VFS来进行文件访问的封装,确实,他的API是统一的.优雅的,支持 ...

  7. Linux虚拟文件系统VFS的相关数据结构和操作

    最近看到几篇介绍VFS的韩语文章,觉得里面的众多绘图清晰易懂,冒昧将其摘选出来,分享给大家,希望大家可以从更多的角度去理解和认识VFS的构成和原理.原文地址位于 https://m.blog.nave ...

  8. linux内核源码分析之虚拟文件系统VFS(一)

    目录 一.文件系统类型 二.VFS虚拟文件系统 三.VFS中主要的对象类型 四.结构体之间的关系 五.inode 节点 一.文件系统类型 基于磁盘的文件系统:在非易失介质上存储文件,在多次会话间保持文 ...

  9. Linux·VFS虚拟文件系统

    目录 1 概念 2 架构 3 接口适配示例 4 跨设备/文件系统示例 5 VFS的抽象接口 6 Linux系统VFS支持的文件系统 7 统一文件模型(common file model) 7.1 Su ...

最新文章

  1. python随机生成车牌_使用Python自动化获取全国每个城市的车牌代码
  2. android开发rn插件,在Android原生应用中嵌入React Native
  3. 直方图应用:直方图均衡化,直方图匹配,对比直方图
  4. java 路径中代替斜杠_老生常谈java路径中的反斜杠和斜杠的区别
  5. Java面试易错题精选
  6. 大学机器人类公选课(ROS机器人高效编程)申请表、大纲、部分教案、进度表等材料分享
  7. 51单片机汇编程序,温度报警项目
  8. 连接中国移动彩信网关发送彩信
  9. java 长链接转短链接_java长链接转短链接代码和如何跳转使用
  10. Tikhonov regularization 吉洪诺夫 正则化
  11. linux 蓝牙打印机
  12. 月入2万的10个小生意项目
  13. 基于 MaxCompute+PAI 的用户增长方案实践
  14. Java基础:说说Java
  15. 打开Flutter动画的另一种姿势——Flare,android面试题选择题
  16. shell脚本一键装机(pxe配合kickstart无人值守)
  17. 【ha知识两问】ha软件是什么?ha软件用途有哪些?
  18. 201421440018王坤的作业一
  19. Beyond Compare中文乱码怎么办
  20. mysql中RowNum的实现

热门文章

  1. 应用迁移:源码迁移 Porting Advisor应用迁移
  2. linux top显示CPU占用高,Steal高
  3. 熊掌记导出html没有换行,Bear|熊掌记:标签使用指南
  4. 全球5G产业链布局与供应商分析
  5. Android 点击键盘外的区域收起键盘
  6. 禁用360浏览器6.2自带的Flash Player
  7. C++输入输入字符串的几种方法
  8. 液晶显示器花屏怎样解决
  9. 计算机网络学习笔记(汇总)
  10. 分布式和集群区别与分布式的应用场景