首页 > 其他分享 >虚拟文件系统

虚拟文件系统

时间:2023-06-15 10:23:16浏览次数:43  
标签:文件 缓存 文件系统 VMA 描述符 虚拟 file

虚拟文件系统

虚拟文件系统是负责组织和管理文件系统的,就像虚拟内存用来实现管理内存系统.而在计算机中因为存储介质的问题,所以通常存在多个文件系统.

比如:硬盘,光盘,闪盘这些存储介质的不同,还有例如一些操作系统的不同,以及文件特性的不同,因此不同的文件系统在实现上会有所不同.

文件系统存储样貌

  • 虚拟文件系统和文件系统类似,也有着自己的数据结构:超级块,inode,目录项等,也就如同文件系统去保存着相应文件的数据那样,有着相应的内存结构。而正是通过这种类似的结构,虚拟文件系统才得以提供给文件系统一种通用的接口供他们使用。

1.虚拟文件系统定义在文件系统的方法

当我们想要读取一个文件或者想要打开一个文件的时候,通常都需要依靠VFS为我们提供的文件接口,让他们得以读写打开及关闭.

例如:当我们使用C语言去打开一个文件,或者读写时

虚拟文件系统

  1. 打开文件:

    #include <stdio.h>
    
    int main() {
        FILE* file = fopen("file.txt", "r");
        if (file == NULL) {
            perror("Error opening file");
            return 1;
        }
        // 文件已成功打开,可以进行读取操作
        // ...
        fclose(file); // 关闭文件
        return 0;
    }
    
  2. 读取文件:

    #include <stdio.h>
    
    int main() {
        FILE* file = fopen("file.txt", "r");
        if (file == NULL) {
            perror("Error opening file");
            return 1;
        }
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), file) != NULL) {
            // 对每一行数据进行处理
            // ...
        }
        fclose(file);
        return 0;
    }
    
  3. 写入文件:

    #include <stdio.h>
    
    int main() {
        FILE* file = fopen("file.txt", "w");
        if (file == NULL) {
            perror("Error opening file");
            return 1;
        }
        fputs("Hello, World!", file);
        fclose(file);
        return 0;
    }
    
  4. 关闭文件:在打开文件中已经有所展示.

而这些编程语言的实习从设计架构上是类似与VFS和文件系统上对于文件操作上的函数的

  • 了解原型,参考Linux系统中VFS中相关的几个函数原型:

    1. int (*open)(struct inode *inode, struct file *filp)

      open函数是VFS中的方法,用于打开文件。它接受一个inode结构体指针和一个file结构体指针作为参数。inode结构体代表文件的元数据信息,而file结构体代表打开的文件实例。函数的返回值是一个整数,表示打开文件的结果。

    2. ssize_t (*read)(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)

      read函数是VFS中的方法,用于从打开的文件中读取数据。它接受一个file结构体指针、一个用户空间缓冲区指针buf、要读取的字节数count,以及一个文件偏移指针f_pos作为参数。函数的返回值是一个ssize_t类型的整数,表示实际读取的字节数。

    3. ssize_t (*write)(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)

      write函数是VFS中的方法,用于向打开的文件中写入数据。它接受一个file结构体指针、一个指向要写入数据的用户空间缓冲区的指针buf、要写入的字节数count,以及一个文件偏移指针f_pos作为参数。函数的返回值是一个ssize_t类型的整数,表示实际写入的字节数。

    4. int (*release)(struct inode *inode, struct file *filp)

      release函数是VFS中的方法,用于关闭打开的文件。它接受一个inode结构体指针和一个file结构体指针作为参数。该函数的返回值是一个整数,表示关闭文件的结果。

  • 路径解析:在程序运行开始,我们去调用fopen时,其里面放入的文件路径或者文件名,会被转换成一个对应的问文件描述符,然后使用文件描述符对文件进行其他操作.

    首先根据参数的类型,大致上有两类:文件路径(绝对路径),文件名(相对路径).

    因此这个解析过程,他会将这个字符串参数递交给VFS,最后递交给底层的操作系统.

    1. 如果是文件路径的方式,比如/home/list/file.txt,他会先从根目录开始查找,也就是/,在这个过程中,文件的查找同样存在缓存,同时更像缓存,当缓存中不存在此文件的索引时,才会继续向下寻找,寻找/llist目录,即使最后找到了这个文件,VFS也会去校验,比如当前程序是否有权限打开时,例如你去打开某些目录下的文件,将权限设置为不可读的状态,那么依然会打开失败.同样,若这个文件在目录项中不管是符号链接还是硬链接,都会根据目录项中的inode号查找对应的文件.
    2. 如果是文件名的方式,比如file.txt,他会从当前目录开始查找,因此也就是相对路径的方式,至于其查找过程其实与通过文件路径的方式相同,只不过这个当前目录是进程在执行的当前目录,即进程在进行文件操作时默认的相对路径的基准目录,因此每一个进程其实都有一个相对应的工作目录.
  • 文件描述符:在程序执行之后,会返回一个与之对应的文件描述符,这个文件描述符实际上是一个整数,没有错,但这个整数指向了文件描述结构,而存储这些文件描述结构就被统称位一张文件描述符表,因此就如同结构体一样类似,即可通过索引确定各自文件的描述结构,而结构里的变量则存放着文件相应的信息.

    #include <stdio.h>
    
    #define MAX_FILE_DESCRIPTORS 1024
    
    typedef struct {
        int fd;            // 文件描述符
        int flags;         // 文件打开标志
        off_t offset;      // 文件偏移量
        // 其他与文件相关的信息
    } FileDescriptorEntry;
    
    typedef struct {
        FileDescriptorEntry entries[MAX_FILE_DESCRIPTORS]; // 文件描述符表的条目数组
        int count;                                        // 当前文件描述符表中的条目数
    } FileDescriptorTable;
    

    以上,仅仅一个实例,通过结构体的方式可以更好地理解文件描述符

    • 注:只有当一个文件被打开或者使用,对应的文件描述符结构才会与之创建,Linux默认一般大小是1024,因此文件描述符表如果为每一份文件都创造一个文件描述符结构来存储相应的数据是没有意义的.

    明明文件有对应的inode和目录项,为什么还需要文件描述符表?

  • 文件描述符表在操作系统中的作用是提供一种机制来跟踪和管理打开的文件。它是为了方便进程对文件的访问和操作而引入的。因此,设计的本质之处是为了让应用进程与操作系统之间有一个认证关系,如果应用程序没有这一层认证关系,那么文件的安全性就无法得到保障,导致进程肆无忌惮地使用任何文件,因此在应用进程使用文件时,必须首先获得文件描述符,同时,也可以通过文件描述符表监控每一个进程所打开的对应的文件,起到了一定的追踪作用,对资源可以进行一定的监视.


2.页缓存

其实缓存这一机制不光提高了速度,即减少了访问时间和操作,其另一个很重要的方面就是他细化了粒度,我们的文件被持久化放入硬盘,而根据我们对硬盘空间的划分,成了对应的块,而每个块512个字节或者4KB的大小,这种块内存内部的浪费是必然会发生的,因此使用缓存,将粒度细化,更重要更常用的文件数据则被记录了下来,且浪费的空间相比于更高层次的磁盘来说节省了不少,还提高了利用率.

因此面对文件最基本的两个功能:读写操作时,则通过施加缓存的方式来提高系统的性能

  1. 读取缓存:当应用程序请求读取文件时,操作系统会首先检查页缓存中是否已经缓存了所需的数据。如果数据已经在页缓存中,操作系统会直接从缓存中将数据拷贝到应用程序的内存空间中,避免了对磁盘的实际读取操作。
  2. 写入缓存:当应用程序请求写入文件时,操作系统会先将数据写入页缓存中,然后在合适的时机再将数据刷新到磁盘中。这种延迟写入(Deferred Write)的策略可以提高写入的效率,避免频繁地访问磁盘。

而面对写入缓存时需要注意的是,如果在写入缓存时,发生了不可控意外,也就是断电,此时保存在主存中的数据还未来得及持久化进硬盘,则会造成数据的丢失,为此,操作系统会有相应的策略去尽可能降低这种风险:比如日志

  • 脏页:指在页缓存中已被修改但尚未写回到磁盘的页。当应用程序对页缓存中的数据进行写操作时,对应的页就会变为脏页。

    而这种内存与磁盘数据不一致性的问题,就称之为脏页

页缓存

2.1内存映射

本质上就是不再需要通过读写接口去访问文件,而是依赖于虚拟内存,通过虚拟地址去访问所需要的文件数据:

大致流程就是这样:在处理内存映射请求时,VFS会分配对应的VMA结构,用VMA结构与文件inode进行关联,最后返回给一个虚拟地址给应用进程.但如果此时内存中并未更新页表,也就是并未有此页,即会发生缺页中断(首次),会根据VMA结构中记录的inode信息,调用对应的文件系统进行处理,文件系统则可以从对应文件的页缓存中找到对饮的内存页返回给VFS,VFS将页缓存中的物理地址写入页表,至此,映射关系就此建立.

什么是VMA结构?

  • VMA:操作系统的一种数据结构,每一个进程都有一个,记录了进程的虚拟地址空间的不同区域的属性和状态。

    VMA 表中的每个条目对应着进程虚拟地址空间中的一个连续的区域,该区域可能包含了进程的代码、数据、堆、栈以及其他映射的文件或设备等。每个 VMA 表项通常包含以下信息:

    • 起始地址和结束地址:指定了该 VMA 区域在进程虚拟地址空间中的范围。
    • 权限和属性:指定了对该 VMA 区域的访问权限,如可读、可写、可执行等,以及其他属性如共享、私有等。
    • 文件映射信息:如果该 VMA 区域与文件映射相关联,记录了文件描述符、偏移量等相关信息。
    • 内存回收信息:记录了该 VMA 区域是否可回收、是否是脏页等信息。
#include <stdio.h>

struct VMA {
    unsigned long start;        // 区域起始地址
    unsigned long end;          // 区域结束地址
    int permissions;            // 区域访问权限
    // 其他属性字段...
};
  • 从这方面来看,VMA和文件描述符表有着相似之处,他们都是基于对文件的一种管理,而VMA偏向于对虚拟地址的管理和访问,而文件描述符更偏向于追踪文件的使用状态及情况.

标签:文件,缓存,文件系统,VMA,描述符,虚拟,file
From: https://www.cnblogs.com/looktheworld/p/17482135.html

相关文章

  • 安装创建虚拟机及VM tools
    安装下载地址https://www.vmware.com/cn/products/workstation-pro/workstation-pro-evaluation.html 点击下一步即可 注意安装位置,只点击控制台,用户体验设置因为不是最新版原因全都不点 点击安装 点击许可证百度一个密钥输入即可例如ZF3R0-FHED2-M80TY-8QY......
  • 关于xfs文件系统uuid的修改方法
    场景1:系统中有两个文件系统的uuid是一样(UUID 是通用唯一识别码(UniversallyUniqueIdentifier)的缩写)场景2:因一些特殊的原因,需要将文件系统的uuid修改成特定的uuid 当然场景1,其实也可以通过笔者另一篇文章中讲到的使用 mount-onouuid/dev/nvme1n1/nvme1n1的方式解......
  • 01企业项目开发流程,你平时的工作流程,pip永久换源,虚拟环境和虚拟环境搭建,luffy后台创建
    1企业项目类型#1面向互联网用户:商城类项目 -微信小程序商城-app商城-得物-饿了么-问卷网#2面向互联网用户:二手交易类的 -咸鱼 -转转#3公司内部项目:python写的重点#传统软件行业,互联网 -给客户做软件:国家电网,社保局,银行,医院,大客户......
  • 搭建虚拟环境
    1.简介描述:不同的虚拟环境相互独立,防止出现包管理混乱和版本冲突2.windows下创建新建文件夹切换到新建的文件夹下下载虚拟环境在当前文件夹下使用自带的虚拟环境:python-mvenvvirtual_env使用:pipinstallvirtualenv,创建文件夹:virtualenvxxx(文件夹的名称)......
  • 配置云主机swap虚拟内存
    配置云主机虚拟内存:ddif=/dev/zeroof=/mnt/swapbs=block_sizecount=number_of_blockddif=/dev/zeroof=/mnt/swapbs=1Mcount=8192mkswap/mnt/swapswapon/mnt/swapvi/etc/fstab/mnt/swapswapswapdefaults00vi/etc/sysctl.confvm.swappiness=60sysctl-p swa......
  • 关于xfs文件系统-在操作系统中遇到两个uuid一样的-挂载报错-wrong fs type, bad optio
    当操作系统中,出现了两个uuid一样的文件系统(笔者这里是xfs),那么默认就只能挂载成功一个[root@qq-5201351~]#blkid|grepxfs|grep1ea9e784-0692-403c-bed1-bf34a5a86a57/dev/nvme1n1:UUID="1ea9e784-0692-403c-bed1-bf34a5a86a57"BLOCK_SIZE="512"TYPE="xfs"/dev/nvme2......
  • 关于磁盘与分区-创建xfs文件系统时指定UUID的方法
    关于在linux系统中对于xfs文件系统创建后,可以通过指定文件系统uuid的方式进行挂载[root@qq-5201351~]#mount-U5a85ee6b-2866-4832-8fea-475d7c8b561c/data01[root@qq-5201351~]#mount-txfs-U5a85ee6b-2866-4832-8fea-475d7c8b561c/data02[root@qq-5201351~]#mou......
  • Network File System 网络文件系统(centos 6)
    预备知识:1 什么是程序、进程、线程?程序:安装的软件就是程序进程:运行的程序---就是进程线程:运行的程序同时完成多个任务2 NFS三个主要组件?Rpc.nfsd  :它是基本的NFS守护进程,主要功能是管理客户端是否能够登录服务器;(由nfs进程实现)Rpc.mount:主要功能是管理NFS......
  • 深入剖析创建Java虚拟机的实现方法
    经过前文《深入剖析java.c文件中JavaMain方法中InitializeJVM的实现》的分析,找到了创建Java虚拟机具体实现的方法Threads::create_vm((JavaVMInitArgs*)args,&can_try_again)。该方法的实现在src\hotspot\share\runtime\threads.cpp文件,我去掉了部分英文注释和宏条件代码,代码更......
  • 关于mkfs.xfs创建xfs文件系统指定block-size为512字节时报错-Minimum block size for
    今天笔者看到mkfs.xfs命令的帮助文档手册时,有如下一段内容可以通过-bsize=value的方式指定block的大小,默认值是4096bytes,最小为512,最大为65536Thedefaultvalueis4096bytes(4KiB),  theminimumis512,andthemaximumis65536(64KiB).于是笔者就尝试,创建x......