精华内容
下载资源
问答
  • 本文详细分析了文件系统、文件结构、虚拟文件系统的定义及作用、VFS与文件系统的关系。分析当中加入了很多自己的理解,重点分析了文件的结构,虚拟文件系统(VFS)与文件系统、用户程序的关系,分析的比较通俗。

    文件系统

          文件系统是对一个存储设备上的数据和元数据进行组织的机制。可以理解成文件系统是对文件的存储、读取、管理等。

         从系统的角度,文件系统是对文件存储空间进行组织分配、负责文件的存储并对存入的文件进行保护和检索的系统。

           用户的角度,当我们需要保存数据或信息时候,我们只需要提供存放文件的路径和文件名,借助文件系统就可以在磁盘上面找到该文件的物理位置。

     说明:

         Linux系统中存在很多的文件系统,例如常见的:ext2,ext3,sysfs,rootfs,proc等。每一个文件系统都是相互独立的,都有自己的组织方式。

     文件结构

       文件结构是文件存放在磁盘等存储设备的组织方法。顾名思义文件结构,联想我们通常所说的装修房子的结构,就是房子的房间布局、规划。同理,文件结构就是怎样将不同的文件有机的组织起来,Linux系统中文件很多,像系统的配置文件、设备文件等,这些必须要有一种结构将他们组织起来,以方便我们管理,这里的文件结构就是起这个作用。

     虚拟文件系统

           虚拟文件系统,作为内核子系统,为用户空间程序提供文件和文件系统相关的接口。虚拟文件系统(VFS是物理文件系统与服务之间的一个接口层,它对Linux的每个文件系统的所有细节进行抽象,使得不同的文件系统在Linux核心以及系统中运行的其他进程看来,都是相同的。严格说来,VFS并不是一种实际的文件系统。它只存在于内存不存在于任何外存空间VFS在系统启动时建立,在系统关闭时消亡。

       说明:

    ⑴ 虚拟,两字说明文件系统在磁盘(或者其他存储介质上)并没有对应的存储信息。准确的讲VFS是一种软件机制,只存在内存中。

    “虚”的VFS的信息都源于“实”的文件系统,所以VFS必须承载各种文件系统的共有属性。

    这些“实”的文件系统只有安装在系统中,VFS才予以认可VFS只管理挂载在系统的实际的文件系统。

    这些“实”的文件系统是按需被挂载的,并不是一次性挂载。

        作用:

    通过虚拟文件系统,程序可以利用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作。

    ⑵通过VFS,它将不同的文件系统抽象后采用统一的方式进行操作。这样用户上层应用就可以采用统一的系统调用而不用考虑底层不同的调用方法。

    ⑶内核在VFS的底层文件系统接口上建立了一个抽象层,其定义了所以文件系统都支持的、基本、概念上的接口和数据结构,所以能链接各种各样的文件系统。

    ⑷总的来说,VFS是一种软件机制VFS是文件系统组织管理中的一个抽象层

      

                                                          

                                                                                VFS与具体文件系统之间的关系

        自己类比理解:

           虚拟文件系统给用户空间提供统一的接口,在这里我们可以把虚拟文件系统这个机制理解成淘宝这个平台,把用户空间理解成买家。淘宝(VFS)负责将整个购物流程抽象成简单的接口,提供相应的接口给买家(用户空间),这些接口我们可以理解成付款接口:支付宝网银接口、商家网站地址、商品搜索查询接口、快递流程查询接口等。买家不用去管这些商品怎么被用户搜索到,不用管钱是怎样在支付宝中流转、不用管物流等。

        这里的具体的文件系统可以理解成各种不同的商家,这些是实实在在的,他们有具体的货物,没有货物谈何交易。淘宝(VFS)这个机制利用抽象层,使得不同的商家,无论是卖零食、电器、书籍等可以有机的连接起来。

        总的来说,内核通过VFS(淘宝平台)可以毫不费力把任何文件系统(不同商家)协同起来工作,并且给用户空间(买家)提供接口(购物入口)。

     参考文献:

     Linux 内核设计与实现

     

    展开全文
  • 虚拟文件系统

    千次阅读 2010-06-01 19:19:00
    通过所谓的虚拟文件系统概念,Linux使用与其他Unix变体相同的方式设法支持多种文件系统类型。 虚拟文件系统所隐含的思想是把表示很多不同种类文件系统的共同信息放入内核;其中有一个字段或函数来支持Linux所支持的...

    现在我们的主流价值观是社会和谐、世界和谐。同样,Linux成功的关键因素之一是它具有与其他操作系统和谐共存的能力。你能够透明地安装具有其他操作系统文件格式的磁盘或分区,这些操作系统如Windows、其他版本的Unix,甚至像Amiga那样的市场占有率很低的系统。通过所谓的虚拟文件系统概念,Linux使用与其他Unix变体相同的方式设法支持多种文件系统类型。

    虚拟文件系统所隐含的思想是把表示很多不同种类文件系统的共同信息放入内核;其中有一个字段或函数来支持Linux所支持的所有实际文件系统所提供的任何操作。对所调用的每个读、写或其他函数,内核都能把它们替换成支持本地Linux文件系统、NTFS文件系统,或者文件所在的任何其他文件系统的实际函数。

    1 虚拟文件系统概述


    虚拟文件系统(Virtual Filesystem)也可以称之为虚拟文件系统转换(Virtual Filesystem Switch,VFS),是一个内核软件层,用来处理与Unix标准文件系统相关的所有系统调用。其健壮性表现在能为各种文件系统提供一个通用的接口。

    例如,假设一个用户输入以下shell命令:
    $ cp /floppy/TEST /tmp/test

    其中/floppy是MS-DOS磁盘的一个安装点,而/tmp是一个标准的第二扩展文件系统(second Extended Filesystom, Ext2)的目录。正如图(a)所示,VFS是用户的应用程序与文件系统实现之间的抽象层。因此,cp程序并不需要知道/floppy/TEST 和 /tmp/test是什么文件系统类型。相反,cp程序直接与VFS交互,这是通过Unix程序设计人员都熟悉的普通系统调用来进行的。cp的执行代码如图(b)所示:


    VFS支持的文件系统可以划分为三种主要类型:

    磁盘文件系统

    这些文件系统管理在本地磁盘分区中可用的存储空间或者其他可以起到磁盘作用的设备(比如说一个USB闪存)。VFS支持的基于磁盘的某些著名文件系统还有:

    - Linux使用的文件系统,如广泛使用的第二扩展文件系统(Ext2),新近的第三扩展文件系统(Third Extended Filesystem,Ext3)及Reiser文件系统(ReiserFS)

    - Unix家族的文件系统,如sysv文件系统(System V、Coherent、Xenix)、UFS(BSD、Solaris、NEXTSTEP),MINIX文件系统及VERITAS VxFS(SCO UnixWare)。

    - 微软公司的文件系统,如MS-DOS、VFAT(Windows 95及随后的版本)及NTFS(Windows NT以及随后的版本)。

    - IS09660 CD-ROM文件系统(以前的High Sierra文件系统)和通用磁盘格式(UDF)的DVD文件系统。

    - 其他有专利权的文件系统,如HPFS(IBM公司的OS/2)、HFS(苹果公司的Macintosh)、AFFS(Amiga公司的快速文件系统)以及ADFS(Acorn 公司的磁盘文件归档系统)。

    - 起源于非Linux系统的其他日志文件系统,如IBM的JFS和SGI的XFS。

    网络文件系统


    这些文件系统允许轻易地访问属于其他网络计算机的文件系统所包含的文件。虚拟文件系统所支持的一些著名的网络文件系统有:NFS、Coda、AFS(Andrew文件系统)、CIFS(用于Microsoft Windows的通用网络文件系统)以及NCP(Novell公司的NetWare Core Protocol)。

    特殊文件系统

    这些文件系统不管理本地或者远程磁盘空间。/proc、/sys、/dev等文件系统是特殊文件系统的一个典型范例。

    Unix的目录建立了一棵根目录为“/”的树。根目录包含在根文件系统(root filesystem)中,在Linux中这个根文件系统通常就是Ext2或Ext3类型。其他所有的文件系统都可以被“安装”在根文件系统的子目中。当一个文件系统被安装在某一个目录上时,在父文件系统中的目录内容不再是可访问的了,因为任何路径(包括安装点),都将引用已安装的文件系统。但是,当被安装文件系统卸载时,原目录的内容又可再现。

    所以,Unix文件系统的一个重要特点就是可以由系统管理员用来隐藏文件,他们只需把一个文件系统安装在要隐藏文件的目录中即可。

    基于磁盘的文件系统通常存放在块设备中,如硬盘、软盘或者CD-ROM。Linux VFS的一个有用特点是能够处理如/dev/loop0这样的虚拟块设备,这种设备可以用来安装普通文件所在的文件系统。作为一种可能的应用,用户可以保护自己的私有文件系统,因为可以通过把自己文件系统的加密版本存放在一个普通文件中来实现。

    第一个虚拟文件系统包含在1986年由Sun公司发布的SunOS操作系统中。从那时起,多数UNIX文件系统都包含VFS。然而,Linux的VFS支持最广泛的文件系统。

    2 通用文件模型


    VFS所隐含的主要思想在于引入了一个通用的文件模型(common file model),这个模型能够表示所有支持的文件系统。该模型严格反映传统Unix文件系统提供的文件模型。这并不奇怪,因为Linux希望以最小的额外开销运行它的本地文件系统。不过,要实现每个具体的文件系统,必须将其物理组织结构转换为虚拟文件系统的通用文件模型。

    例如在通用文件模型中,每个目录被看作一个文件,可以包含若干文件和其他的子目录。但是,存在几个非Unix的基于磁盘的文件系统,它们利用文件分配表(File Allocation Table,FAT)存放每个文件在目录树中的位置,在这些文件系统中,存放的是目录而不是文件。为了符合VFS的通用文件模型,对上述基于FAT的文件系统的实现,Linux必须在必要时能够快速建立对应于目录的文件。这样的文件只作为内核内存的对象而存在。

    从本质上说,Linux内核不能对一个特定的函数进行硬编码来执行诸如read()或ioctl()这样的操作,而是对每个操作都必须使用一个指针,指向要访问的具体文件系统的适当函数。

    为了进一步说明这一概念,参见前面的那个图,其中显示了内核如何把read()转换为专对MS-DOS文件系统的一个调用。应用程序对read()的调用引起内核调用相应的sys_read()服务例程,这与其他系统调用完全类似。我们在本章后面会看到,文件在内核内存中是由一个file数据结构来表示的。这种数据结构中包含一个称为f_op的字段,该字段中包含一个指向专对MS-DOS文件的函数指针,当然还包括读文件的函数。

    sys_read()查找到指向该函数的指针,并调用它。这样一来,应用程序的read()就被转化为相对间接的调用:
    file->f_op->read(…);

    与之类似,write()操作也会引发一个与输出文件相关的Ext2写函数的执行。简而言之,内核负责把一组合适的指针分配给与每个打开文件相关的file变量,然后负责调用针对每个具体文件系统的函数(由f_op字段指向)。

    你可以把通用文件模型看作是面向对象的,在这里,对象是一个软件结构,其中既定义了数据结构也定义了其上的操作方法。出于效率的考虑,Linux的编码并未采用面向对像的程序设计语言(比如C++)。因此对象作为普通的C数据结构来实现,数据结构中指向函数的字段就对应于对象的方法。

    通用文件模型由下列对象类型组成:

    超级块对象(superblock object):存放已安装文件系统的有关信息。对基于磁盘的文件系统,这类对象通常对应于存放在磁盘上的文件系统控制块(filesystem control block)。

    索引节点对象(inode object):存放关于具体文件的一般信息。对基于磁盘的文件系统,这类对象通常对应于在磁盘上的文件控制块(file control block)。每个索引节点对象都有一个索引节点号,这个节点号唯一地标识文件系统中的文件。

    文件对象(file object):存放打开文件与进程之间进行交互的有关信息。这类信息仅当进程访问文件期间在于内核内存中。

    目录项对象(dentry object):存放目录项(也就是文件的特定名称)与对应文件进行链接的有关信息。每个磁盘文件系统都以自己特有的方式将该类信息存在磁盘上。

    下图所示是一个简单的示例,说明进程怎样与文件进行交互。


    三个不同进程已经打开同一个文件,其中两个进程使用同一个硬链接。在这种情况下,其中的每个进程都使用自己的文件对象,但只需要两个目录项对象,每个硬链接对应一个目录项对象。这两个目录项对象指向同一个索引节点对象,该索引节点对象标识超级块对象,以及随后的普通磁盘文件。

    VFS除了能为所有文件系统的实现提供一个通用接口外,还具有另一个与系统性能相关的重要作用,那就是一些文件相关数据结构的磁盘高速缓存。例如最近最常使用的目录项对象被放在所谓目录项高速缓存(dentry cache)的磁盘高速缓存中,从而加速从文件路径名到最后一个路径分量的索引节点的转换过程。

    一般说来,磁盘高速缓存(disk cache)属于软件机制,它允许内核将原本存在磁盘上的某些信息保存在RAM中,以便对这些数据的进一步访问能快速进行,而不必慢速访问磁盘本身。

    注意,磁盘高速缓存不同于硬件高速缓存或内存高速缓存,后两者都与磁盘或其他设备无关。硬件高速缓存是一个快速静态RAM,它加快了直接对内存,这样的慢速动态RAM的请求。内存高速缓存是一种软件机制,引入它是为了绕过内核内存分配器(slab分配器)。

    除了目录项高速缓存和索引结点高速缓存之外,Linux还使用其他磁盘高速缓存。其中最重要的一种就是所谓的页高速缓存,我们将在本专题中中进行详细介绍。

    3 VFS所处理的系统调用


    下表列出了VFS的系统调用,这些系统调用涉及文件系统、普通文件、目录文件以及符号链接文件:

    系统调用名

    说明

    mount( ) umount( ) umount2( )

    安装/卸载文件系统

    sysfs( )

    获取文件系统信息

    statfs( ) fstatfs( ) statfs64( ) fstatfs64( )

    ustat( )

    获取文件系统统计信息

    chroot( ) pivot_root( )

    更改根目录

    chdir( ) fchdir( ) getcwd( )

    对当前目录进行操作

    mkdir( ) rmdir( )

    创建/删除目录

    getdents( ) getdents64( ) readdir( ) link( )

    unlink( ) rename( ) lookup_dcookie( )

    对目录项进行操作

    readlink( ) symlink( )

    对软链接进行操作

    chown( ) fchown( ) lchown( ) chown16( )

    fchown16( ) lchown16( )

    更改文件所有者性

    chmod( ) fchmod( ) utime( )

    更改文件属性

    stat( ) fstat( ) lstat( ) access( ) oldstat( ) oldfstat( ) oldlstat( ) stat64( ) lstat64( )

    fstat64( )

    读取文件状态

    open( ) close( ) creat( ) umask( )

    打开/关闭/创建文件

    dup( ) dup2( ) fcntl( ) fcntl64( )

    对文件描述符进行操作

    select( ) poll( )

    等待一组文件描述符上发生的事件

    truncate( ) ftruncate( ) truncate64( )

    ftruncate64( )

    更改文件长度

    lseek( ) _llseek( )

    更改文件指针

    read( ) write( ) readv( ) writev( ) sendfile( ) sendfile64( ) readahead( )

    进行文件I/O 操作

    io_setup( ) io_submit( ) io_getevents( ) io_cancel( ) io_destroy( )

    异步I/O (允许多个读和写请求)

    pread64( ) pwrite64( )

    搜索并访问文件

    mmap( ) mmap2( ) munmap( ) madvise( ) mincore( )

    remap_file_pages( )

    处理文件内存映射

    fdatasync( ) fsync( ) sync( ) msync( )

    同步文件数据

    flock( )

    处理文件锁

    setxattr( ) lsetxattr( ) fsetxattr( ) getxattr( ) lgetxattr( ) fgetxattr( ) listxattr( ) llistxattr( ) flistxattr( ) removexattr( ) lremovexattr( ) fremovexattr( )

    处理文件扩展属性



    另外还有少数几个由VFS处理的其他系统调用,诸如ioperm()、ioctl()、pipe()和mknod(),涉及设备文件和管道文件,这些将在后续博文中讨论。最后一组由VFS处理的系统调用,诸如socket()、connect()和bind()属于套接字系统调用,并用于实现网络功能。与表中列出的系统调用还对应的一些内核服务例程,我们会在后面的博文中陆续进行讨论。

    前面我们已经提到,VFS是应用程序和具体文件系统之间的一层。不过,在某些情况下,一个文件操作可能由VFS本身去执行,无需调用低层函数。例如,当某个进程关闭一个打开的文件时,并不需要涉及磁盘上的相应文件,因此VFS只需释放对应的文件对象。类似地,当系统调用lseek()修改一个文件指针,而这个文件指针是打开文件与进程交互所涉及的一个属性时,VFS就只需修改对应的文件对象,而不必访问磁盘上的文件,因此,无需调用具体文件系统的函数。从某种意义上说,可以把VFS看成“通用”文件系统,它在必要时依赖某种具体文件系统。

     

    展开全文
  • 【Linux】Linux的虚拟文件系统

    千次阅读 2018-08-04 20:01:27
    Linux的虚拟文件系统与实际文件系统的关系如下所示:   VFS的原理 各种文件系统之所以有区别,就在于它们的目录文件结构各不相同,随之而来的也就是对文件目录的操作函数也不相同。对于前者可以在保留原系统...

    Linux的虚拟文件系统与实际文件系统的关系如下所示:

     

    VFS的原理

    各种文件系统之所以有区别,就在于它们的目录文件结构各不相同,随之而来的也就是对文件目录的操作函数也不相同。对于前者可以在保留原系统目录结构的基础上,再构建一个新的统一的目录文件结构,而这个新目录文件中的信息是通过提取原系统目录文件信息进行重新组织来建立的。这样,用户面对的就不再是五花八门的目录文件,而是一个统一的目录文件。

    为了让不同文件系统操作函数实现一个统一的操作界面,VFS利用函数指针,因为函数指针实质上就是对函数的一次抽象,如下:

    从上图可见,用户在使用函数指针f()调用函数时,真正被调用的函数为该指针指向的函数,而指针f只是一个替身,或者说,它只是实际函数的一个虚拟表示。换句话说,通过同一个f可以调用不同的函数,至于调用的是哪一个函数,则取决于操作系统使哪个函数与指针f相关联。这也就是说,函数指针可以为多个不同的函数提供一个统一界面。

    使用上述方法,Linux为虚拟文件系统构建了如下结构的函数指针集,以统一操作界面:

    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 (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    	int (*readdir) (struct file *, void *, filldir_t);
    	unsigned int (*poll) (struct file *, struct poll_table_struct *);
    	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    	int (*mmap) (struct file *, struct vm_area_struct *);
    	int (*open) (struct inode *, struct file *);
    	int (*flush) (struct file *, fl_owner_t id);
    	int (*release) (struct inode *, struct file *);
    	int (*fsync) (struct file *, struct dentry *, int datasync);
    	int (*aio_fsync) (struct kiocb *, 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 **);
    };

    用图形表示的file_operations如下所示:

    上图表示的函数指针表,就是VFS提供的用户与实际文件系统之间的接口。也就是说,不论使用什么文件系统,用户面对的都是指针表中的函数指针,至于具体的实际文件系统则取决于与函数指针相关联的具体函数。例如,如果VFS与Ext2系统挂接,那么用户对虚拟文件系统的操作就是对Ext2文件系统的操作,如下图所示:

    当然,如果实际文件系统不支持虚拟文件系统的某个操作,则该指针应该为NULL。

    从上述内容可知,虚拟文件系统既没有文件,也不直接管理文件,它只是用户与实际文件系统之间的接口。因此,它并不需要保存在永久存储介质中,只是在需要时由内核在内存中创建起来的一个文件系统,所以叫做虚拟文件系统。出于系统性能的考虑和设计者的偏好,Linux系统VFS的结构与Ext2基本相同。

    对于上述虚拟文件系统,《Linux内核源代码情景分析》中有如下描述:如果把内核比喻成计算机中的“母板”,把VFS比喻成“母板”上的一个“插槽”,那么每一个具体的文件系统就好像是一块“接口卡”。母板面对的是一个固定的插槽,而使用实际系统则是接口卡,插上什么卡就执行什么功能。

     

    VFS的超级块

    VFS超级块

    所有的实际文件系统,一旦被安装到系统上,就必须由系统在内存为其创建一个虚拟文件系统的超级块。这个超级块实质上也就是系统把实际文件系统超级块的相关信息提取出来(如Ext2的ext2_sb_info),再与虚拟系统所需要的通用信息拼接起来而形成的一个格式统一的超级块,它相当于一个实际文件系统在虚拟文件系统中的身份证。这个虚拟超级块包含如下信息:

    • 设备标识符。这是存储文件系统的物理设备的设备标识符;
    • 节点指针,包括安装i节点指针和覆盖i节点指针。其中,安装i节点指针指向被安装的子文件系统的第一个i节点;覆盖i节点指针则指向被安装文件系统的安装点;
    • 文件数据块的大小;
    • 超级块操作集。这是一组指向超级块操作例程的指针,VFS利用他们可以对超级块和i节点进行访问操作;
    • 所安装的文件系统的类型;
    • 被安装文件系统的一些私有信息。

    虚拟文件系统的超级块在文件include/linux/fs.h中定义如下:

    struct super_block {
    	struct list_head	s_list;		/* 文件超级块链表头指针 */
    	dev_t			s_dev;		/* 文件系统的块设备标识 */
    	unsigned long		s_blocksize;        //数据块的大小
    	unsigned char		s_blocksize_bits;        //块大小值所占的位数
    	unsigned char		s_dirt;        //该值若为1,标识该超级块已被修改
    	unsigned long long	s_maxbytes;	/* 文件大小的最大值 */
    	struct file_system_type	*s_type;        //已注册文件系统的链表指针
    	const struct super_operations	*s_op;        //指向超级块操作函数集的指针
    	struct dquot_operations	*dq_op;
     	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;
    	struct mutex		s_lock;
    	int			s_count;
    	int			s_need_sync_fs;
    	atomic_t		s_active;
    #ifdef CONFIG_SECURITY
    	void                    *s_security;
    #endif
    	struct xattr_handler	**s_xattr;
    
    	struct list_head	s_inodes;	/* all inodes */
    	struct list_head	s_dirty;	/* dirty inodes */
    	struct list_head	s_io;		/* parked for writeback */
    	struct list_head	s_more_io;	/* parked for more writeback */
    	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
    	struct list_head	s_files;
    	/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
    	struct list_head	s_dentry_lru;	/* unused dentry lru */
    	int			s_nr_dentry_unused;	/* # of dentry on lru */
    
    	struct block_device	*s_bdev;
    	struct mtd_info		*s_mtd;
    	struct list_head	s_instances;
    	struct quota_info	s_dquot;	/* Diskquota specific options */
    
    	int			s_frozen;
    	wait_queue_head_t	s_wait_unfrozen;
    	char s_id[32];				/* Informational name */
    
    	void 			*s_fs_info;	/* 指向实际文件系统超级块内核信息结构的指针 */
    	fmode_t			s_mode;
    	struct mutex s_vfs_rename_mutex;	/* Kludge */
    	u32		   s_time_gran;
    	char *s_subtype;
    	char *s_options;
    	struct list_head s_async_list;
    };

    虚拟文件系统的超级块,既包含虚拟文件系统的通用管理信息,也包含具体文件系统的私有信息。其中,结构的指针s_fs_info就指向具体实际文件系统的私有信息,该信息被保存在内存的一个结构中。

    例如:当虚拟文件系统在与Ext2文件系统对接时,指针s_fs_info就指向Ext2文件系统的私有信息结构struct ext2_sb_info。即系统在安装Ext2系统时,会在内存中创建一个struct ext2_sb_info结构实例,将磁盘文件系统Ext2超级块struct ext2_super_block的部分私有信息提取到该结构,并将结构与VFS超级块指针s_fs_info关联起来,如下图所示:

    结构struct ext2_sb_info的定义如下:

    struct ext2_sb_info {
    	unsigned long s_frag_size;	    /* 碎片大小 */
    	unsigned long s_frags_per_block;    /* 每块碎片的数目 */
    	unsigned long s_inodes_per_block;    /* 每块节点数 */
    	unsigned long s_frags_per_group;    /* 块组中的碎片数 */
    	unsigned long s_blocks_per_group;    /* 块组中块的数量 */
    	unsigned long s_inodes_per_group;    /* 块组中的节点数目 */
    	unsigned long s_itb_per_group;	    /* 块组中节点表所占用的块数 */
    	unsigned long s_gdb_count;	    /* 块组描述符表所占用的块数 */
    	unsigned long s_desc_per_block;	    /* 块组描述符数 */
    	unsigned long s_groups_count;	    /* 块组数 */
    	unsigned long s_overhead_last;  /* 块缓冲区指针 */
    	unsigned long s_blocks_last;    /* 指向缓冲区中超级块的指针 */
    	struct buffer_head * s_sbh;	    /* 指向缓冲区中组描述符表的指针 */
    	struct ext2_super_block * s_es;	    /* Pointer to the super block in the buffer */
    	struct buffer_head ** s_group_desc;
    	unsigned long  s_mount_opt;
    	unsigned long s_sb_block;
    	uid_t s_resuid;
    	gid_t s_resgid;
    	unsigned short s_mount_state;
    	unsigned short s_pad;
    	int s_addr_per_block_bits;
    	int s_desc_per_block_bits;
    	int s_inode_size;            //节点大小
    	int s_first_ino;            //第一个节点号
    	spinlock_t s_next_gen_lock;
    	u32 s_next_generation;
    	unsigned long s_dir_count;
    	u8 *s_debts;
    	struct percpu_counter s_freeblocks_counter;
    	struct percpu_counter s_freeinodes_counter;
    	struct percpu_counter s_dirs_counter;
    	struct blockgroup_lock *s_blockgroup_lock;
    
    	spinlock_t s_rsv_window_lock;
    	struct rb_root s_rsv_window_root;
    	struct ext2_reserve_window_node s_rsv_window_head;
    };

    VFS超级块的操作函数集

    依照Linux的设计思想,Linux把有关文件系统超级块的操作函数集中地列写在一个封装了超级块操作函数指针的结构super_operations中,并用VFS超级块结构中的域s_op指向这个结构:

    struct super_operations {
       	struct inode *(*alloc_inode)(struct super_block *sb);
    	void (*destroy_inode)(struct inode *);
    
       	void (*dirty_inode) (struct inode *);
    	int (*write_inode) (struct inode *, int);
    	void (*drop_inode) (struct inode *);
    	void (*delete_inode) (struct inode *);
    	void (*put_super) (struct super_block *);
    	void (*write_super) (struct super_block *);
    	int (*sync_fs)(struct super_block *sb, int wait);
    	int (*freeze_fs) (struct super_block *);
    	int (*unfreeze_fs) (struct super_block *);
    	int (*statfs) (struct dentry *, struct kstatfs *);
    	int (*remount_fs) (struct super_block *, int *, char *);
    	void (*clear_inode) (struct inode *);
    	void (*umount_begin) (struct super_block *);
    
    	int (*show_options)(struct seq_file *, struct vfsmount *);
    	int (*show_stats)(struct seq_file *, struct vfsmount *);
    #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);
    #endif
    	int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
    };

    这个结构与前面介绍的struct file_operations一样,相当于具体文件系统超级块所使用的安装在内核上的“插槽”。

     

    VFS的dentry结构

    结构dentry是实际文件系统的目录项在虚拟文件系统VFS中的对应物,实质上就是前面所讲的目录缓冲区。当系统访问一个具体文件时,会根据这个文件在磁盘上的目录在内存中创建一个dentry结构,它除了要存放文件目录信息之外,还要存放有关文件路径的一些动态信息。

    例如:它建立了文件名与节点inode之间的联系,保存了目录项与其父、子目录之间的关系。之所以建立这样的一个文件目录的对应物,是为了同一个目录被再次访问时,其相关信息就可以直接由dentry获得,而不必再次重复访问磁盘。

    VFS的dentry结构

    结构dentry在文件include/linux/dcache.h中定义如下:

    struct dentry {
    	atomic_t d_count;
    	unsigned int d_flags;		/* 记录目录项被引用次数的计数器 */
    	spinlock_t d_lock;		/* 目录项的标志 */
    	int d_mounted;
    	struct inode *d_inode;		/* 与文件名相对应的inode */
    
    	struct hlist_node d_hash;	/* 目录项形成的散列表 */
    	struct dentry *d_parent;	/* 指向父目录项的指针 */
    	struct qstr d_name;        //包含文件名的结构
    
    	struct list_head d_lru;		/* 已经没有用户使用的目录项的链表 */
    	union {
    		struct list_head d_child;	/* 父目录的子目录项形成的链表 */
    	 	struct rcu_head d_rcu;
    	} d_u;
    	struct list_head d_subdirs;	/* i节点别名的链表 */
    	struct list_head d_alias;	/* inode alias list */
    	unsigned long d_time;		/* used by d_revalidate */
    	const struct dentry_operations *d_op;        //指向dentry操作函数集的指针
    	struct super_block *d_sb;	/* 目录树的超级块,即本目录项所在目录树的根 */
    	void *d_fsdata;			/* 文件系统的特定数据 */
    
    	unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* 短文件名 */
    };
    

    结构中的域d_name是qstr类型的结构。该结构的定义如下:

    struct qstr {
    	unsigned int hash;            //文件名
    	unsigned int len;            //文件名长度
    	const unsigned char *name;        //散列值
    };

    内核通过维护一个散列表dentry_hashtable来管理dentry。系统一旦在内存中建立一个dentry,该dentry结构就会被链入散列表的某个队列中。

    结构中的域d_count记录了本dentry被访问的次数。当某个dentry的d_count的值为0时,就意味着这个dentry结构已经没有用户使用了,这时这个dentry会被d_lru链入一个由系统维护的另一个队列dentry_unused中。由于内核从不删除曾经建立的dentry,于是,同一个目录被再次访问时,其相关信息就可以直接由dentry获得,而不必重复访问存储文件系统的外存。

    另外,当本目录项有父目录节点时,其dentry结构通过域d_child挂入父目录项的子目录d_subdirs队列中,同时使指针d_parent指向父目录的dentry结构。若本目录有子目录,则将它们挂接在域d_subdirs指向的队列中。

    dentry的操作函数

    为了对dentry结构进行操作,系统定义了一个dentry操作函数集,目录项dentry中的域d_op就指向封装了这些操作函数指针的结构:

    struct dentry_operations {
    	int (*d_revalidate)(struct dentry *, struct nameidata *);        //判断目录项是否有效
    	int (*d_hash) (struct dentry *, struct qstr *);            //生成一个散列值
    	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);        //比较两个文件名
    	int (*d_delete)(struct dentry *);        //删除count为0的dentry
    	void (*d_release)(struct dentry *);        //释放一个dentry对象
    	void (*d_iput)(struct dentry *, struct inode *);        //丢弃目录项对应的inode
    	char *(*d_dname)(struct dentry *, char *, int);
    };

    由于在结构中的所有域都是操作函数的指针,因此这个结构相当于一个函数跳转表,系统通过这个函数跳转表来调用所要使用的函数。因此,这个结构相当于具体文件系统目录项所使用的安装在内核的“插槽”。

     

    VFS的i节点

    VFS的i节点简介

    前面谈到,i节点是文件的控制块,它存放文件的基本信息。不同文件系统的i节点结构是不同的,甚至在一些一体化目录结构的文件系统(例如FAT系统)中根本就没有i节点的概念,所以在使用某一个实际文件系统时,内核必须按照虚拟文件系统i节点的格式在内存创建一个VFS的i节点,并根据该实际文件系统的静态数据来填写这个i节点。

    VFS的i节点结构在文件include/linux/fs.h中定义如下:

    struct inode {
    	struct hlist_node	i_hash;            //指向散列表的指针
    	struct list_head	i_list;            //指向i节点链表的这孩子很
    	struct list_head	i_sb_list;
    	struct list_head	i_dentry;            //指向dentry链表的指针
    	unsigned long		i_ino;            //i节点号
    	atomic_t		i_count;            //记录使用本节点进程数目的计数器
    	unsigned int		i_nlink;            //节点连接的别名的数目
    	uid_t			i_uid;            //文件拥有者的标识号
    	gid_t			i_gid;            //文件拥有者所在组的标识号
    	dev_t			i_rdev;            //文件设备的标识号
    	u64			i_version;
    	loff_t			i_size;
    #ifdef __NEED_I_SIZE_ORDERED
    	seqcount_t		i_size_seqcount;
    #endif
    	struct timespec		i_atime;
    	struct timespec		i_mtime;
    	struct timespec		i_ctime;
    	unsigned int		i_blkbits;
    	blkcnt_t		i_blocks;
    	unsigned short          i_bytes;
    	umode_t			i_mode;
    	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
    	struct mutex		i_mutex;
    	struct rw_semaphore	i_alloc_sem;
    	const struct inode_operations	*i_op;        //指向i节点操作函数集的指针
    	const struct file_operations	*i_fop;	        /* 指向文件操作函数集的指针 */
    	struct super_block	*i_sb;            //指向文件系统超级块的指针
    	struct file_lock	*i_flock;
    	struct address_space	*i_mapping;        //指向下一个域i_data的指针
    	struct address_space	i_data;            //页缓冲区头结构
        void *generic_ip;            //指向实际文件节点信息结构的指针
    #ifdef CONFIG_QUOTA
    	struct dquot		*i_dquot[MAXQUOTAS];
    #endif
    	struct list_head	i_devices;
    	union {
    		struct pipe_inode_info	*i_pipe;
    		struct block_device	*i_bdev;
    		struct cdev		*i_cdev;
    	};
    	int			i_cindex;
    
    	__u32			i_generation;
    
    #ifdef CONFIG_DNOTIFY
    	unsigned long		i_dnotify_mask; /* Directory notify events */
    	struct dnotify_struct	*i_dnotify; /* for directory notifications */
    #endif
    
    #ifdef CONFIG_INOTIFY
    	struct list_head	inotify_watches; /* watches on this inode */
    	struct mutex		inotify_mutex;	/* protects the watches list */
    #endif
    
    	unsigned long		i_state;
    	unsigned long		dirtied_when;	/* jiffies of first dirtying */
    
    	unsigned int		i_flags;
    
    	atomic_t		i_writecount;
    #ifdef CONFIG_SECURITY
    	void			*i_security;
    #endif
    	void			*i_private; /* fs or device private pointer */
    };

    与VFS的超级块一样,VFS的i节点也是既包含虚拟文件系统的通用管理系统,又包含具体文件系统i节点的私有信息。其中,结构的指针generic_ip就指向了具体文件系统i节点的私有信息,该信息也被保存在内存的一个结构中。

    例如:当虚拟文件系统与Ext2文件系统对接时,指针generic_ip就指向Ext2文件系统的i节点信息结构ext2_inode_info。即系统在安装Ext2系统时,会在内存中创建一个ext2_inode_info结构实例,并将磁盘文件系统Ext2的i节点的部分私有信息提取到该结构。

    结构struct ext2_inode_info的代码如下:

    struct ext2_inode_info {
    	__le32	i_data[15];            //数据库块指针数组
    	__u32	i_flags;            //文件打开方式
    	__u32	i_faddr;
    	__u8	i_frag_no;            //第一个碎片号
    	__u8	i_frag_size;            //碎片大小
    	__u16	i_state;
    	__u32	i_file_acl;            //文件访问控制链表
    	__u32	i_dir_acl;
    	__u32	i_dtime;            //文件删除时间
    
    	__u32	i_block_group;            //文件所在块组号
    	struct ext2_block_alloc_info *i_block_alloc_info;
    
    	__u32	i_dir_start_lookup;
    #ifdef CONFIG_EXT2_FS_XATTR
    	struct rw_semaphore xattr_sem;
    #endif
    #ifdef CONFIG_EXT2_FS_POSIX_ACL
    	struct posix_acl	*i_acl;
    	struct posix_acl	*i_default_acl;
    #endif
    	rwlock_t i_meta_lock;
    
    	struct mutex truncate_mutex;
    	struct inode	vfs_inode;
    	struct list_head i_orphan;	/* unlinked but open inodes */
    };
    

    当虚拟文件与Ext2文件系统相关联时,VFS的索引节点如下图所示:

    VFS的i节点操作函数

    对于索引节点的操作函数封装在结构inode_operations中。该结构的定义如下:

    struct inode_operations {
    	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);        //创建一个新i节点
    	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);        //查找一个i节点的dentry
    	int (*link) (struct dentry *,struct inode *,struct dentry *);        //创建一个新的硬链接
    	int (*unlink) (struct inode *,struct dentry *);        //删除一个硬链接
    	int (*symlink) (struct inode *,struct dentry *,const char *);
    	int (*mkdir) (struct inode *,struct dentry *,int);
    	int (*rmdir) (struct inode *,struct dentry *);
    	int (*mknod) (struct inode *,struct dentry *,int,dev_t);
    	int (*rename) (struct inode *, struct dentry *,
    			struct inode *, struct dentry *);
    	int (*readlink) (struct dentry *, char __user *,int);
    	void * (*follow_link) (struct dentry *, struct nameidata *);
    	void (*put_link) (struct dentry *, struct nameidata *, void *);
    	void (*truncate) (struct inode *);
    	int (*permission) (struct inode *, int);
    	int (*setattr) (struct dentry *, struct iattr *);
    	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
    	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
    	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
    	ssize_t (*listxattr) (struct dentry *, char *, size_t);
    	int (*removexattr) (struct dentry *, const char *);
    	void (*truncate_range)(struct inode *, loff_t, loff_t);
    	long (*fallocate)(struct inode *inode, int mode, loff_t offset,
    			  loff_t len);
    	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
    		      u64 len);
    };
    

    inode的结构的指针i_op指向这个函数集。

    需要注意的是,inode结构还是要一个指向文件操作函数集struct file_operations的指针i_fop。

     

    文件缓冲区

    与内存相比,处理器读取磁盘数据的速度相当低,只相当于读取内存速度的千分之一,所以为了提高系统效率,Linux要在内存为最近访问的磁盘数据简历文件缓冲区。

    所谓文件缓冲区,就是一块内核内存区域。由于该区域是进程与磁盘之间起缓冲作用的中介,因此缓冲区在与磁盘交换信息时必须以块为访问单位。即从磁盘的角度看,这个缓冲区是磁盘数据块缓冲区,而从进程的角度看,则是页缓冲区。如下图所示:

    因此,内核中设置了两套用来管理缓冲区的数据结构。

    磁盘数据块缓冲区

    在Linux中,每一个磁盘数据块缓冲区用buffer_head结构来描述。buffer_head结构如下:

    struct buffer_head {
    	unsigned long b_state;		/* 缓冲区状态位图 */
    	struct buffer_head *b_this_page;/* 指向同一页面的缓冲块,形成环形链表 */
    	struct page *b_page;		/* 指向页缓冲指针 */
    
    	sector_t b_blocknr;		/* 逻辑块号 */
    	size_t b_size;			/* 块大小 */
    	char *b_data;			/* 指向数据块缓冲区的指针 */
    
    	struct block_device *b_bdev;        //指向块设备结构的指针
    	bh_end_io_t *b_end_io;		/* I/O completion */
     	void *b_private;		/* reserved for b_end_io */
    	struct list_head b_assoc_buffers; /* associated with another mapping */
    	struct address_space *b_assoc_map;	/* mapping this buffer is
    						   associated with */
    	atomic_t b_count;		/* 块引用计数 */
    };

    其中,域b_data是指向内存中磁盘块缓冲区的指针;域b_size表示缓冲区的大小。由于进程以页面为单位来访问缓冲区,所以结构中用域b_this_page把同一页面缓冲块组成了一个环形链表。

    另外,系统根据磁盘数据块缓冲区的使用状态将它们分别组成了多个队列。

    内存中的一个磁盘块缓冲区的队列示意图如下所示:

    磁盘数据块缓冲区是一种全局资源,可以被所有的文件系统共享使用。

    页缓冲区

    为了方便进程对文件的使用,并在需要时能把以块为单位的磁盘块缓冲区(块的大小一般为512字节)映射到以页为单位(页的大小一般4k)的用户空间,VFS还建立了页缓冲区。由于进程是通过VFS的i节点来访问文件的,因此,文件的页缓冲区也就被设置在inode结构中。

    inode结构中有一个指向自身的i_data域的指针i_mapping,这个i_data域是一个address_space的结构。而每一个页面的所有信息由struct page来描述,它有一个名称为mapping的域,这是一个指针,它指向一个struct address_space类型结构。

    缓冲区的数据结构struct address_space的主要内容如下:

    struct address_space {
    	struct inode		*host;		    /* 属主的索引节点 */
    	struct radix_tree_root	page_tree;	        /* 全部页面的radix数 */
    	spinlock_t		tree_lock;	        /* and lock protecting it */
    	unsigned int		i_mmap_writable;        /* count VM_SHARED mappings */
    	struct prio_tree_root	i_mmap;		    /* tree of private and shared mappings */
    	struct list_head	i_mmap_nonlinear;        /*list VM_NONLINEAR mappings */
    	spinlock_t		i_mmap_lock;	    /* protect tree, count, list */
    	unsigned int		truncate_count;	    /* Cover race condition with truncate */
    	unsigned long		nrpages;	    /* 占用的物理边框总数 */
    	pgoff_t			writeback_index;        /* writeback starts here */
    	const struct address_space_operations *a_ops;	    /* 页缓冲区操作函数集指针 */
    	unsigned long		flags;		    /* error bits/gfp mask */
    	struct backing_dev_info *backing_dev_info;     /* 预读信息 */
    	spinlock_t		private_lock;	    /* for use by the address_space */
    	struct list_head	private_list;	    /* 页缓冲区链表 */
    	struct address_space	*assoc_mapping;	    /* 相关缓存 */
    } __attribute__((aligned(sizeof(long))));

    页缓冲区与磁盘块缓冲区之间的关系如下图所示:

    依照Linux的一贯风格,Linux将缓冲区操作函数封装在如下的address_space_operations结构中:

    struct address_space_operations {
    	int (*writepage)(struct page *page, struct writeback_control *wbc);
    	int (*readpage)(struct file *, struct page *);
    	void (*sync_page)(struct page *);
    
    	/* Write back some dirty pages from this mapping. */
    	int (*writepages)(struct address_space *, struct writeback_control *);
    
    	/* Set a page dirty.  Return true if this dirtied it */
    	int (*set_page_dirty)(struct page *page);
    
    	int (*readpages)(struct file *filp, struct address_space *mapping,
    			struct list_head *pages, unsigned nr_pages);
    
    	int (*write_begin)(struct file *, struct address_space *mapping,
    				loff_t pos, unsigned len, unsigned flags,
    				struct page **pagep, void **fsdata);
    	int (*write_end)(struct file *, struct address_space *mapping,
    				loff_t pos, unsigned len, unsigned copied,
    				struct page *page, void *fsdata);
    
    	/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
    	sector_t (*bmap)(struct address_space *, sector_t);
    	void (*invalidatepage) (struct page *, unsigned long);
    	int (*releasepage) (struct page *, gfp_t);
    	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
    			loff_t offset, unsigned long nr_segs);
    	int (*get_xip_mem)(struct address_space *, pgoff_t, int,
    						void **, unsigned long *);
    	/* migrate the contents of a page to the specified target */
    	int (*migratepage) (struct address_space *,
    			struct page *, struct page *);
    	int (*launder_page) (struct page *);
    	int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
    					unsigned long);
    };
    

    通常,i_fop(inode的指向文件操作函数集的指针)并不直接与块设备联系,而是间接通过a_ops(address_space的页缓冲区操作函数集)读写文件。文件的页缓冲就是i_fop与a_ops之间的缓冲,它是块设备缓冲之上的更高一级缓冲,直接用于具体文件的读写。

     

    Linux的Proc文件系统

    从原理上来讲,计算机中凡是能够提供信息和接受信息的设备或者主体,都可以被抽象成文件。计算机应用程序经常需要了解Linux内核和正在运行进程的当前状态和信息,并且希望能对这些信息做简单的修改。为此,Linux创建了一个专门提供上述信息的文件系统——Proc文件系统,该文件系统具有固定的安装点/proc,所以有时也把它叫做/proc文件系统。

    Proc是一种特殊的文件系统。说它特殊,是因为它的文件并不像普通文件那样存放在外存储器中,它只是存在于内存中的一种文件。同样,在外存储器中也不存在这个文件系统的目录和节点,它们也只存在于内存。当系统关闭之后,Proc文件系统包括其中所有的文件也就不复存在了。

    实质上,Proc文件就是一个特殊的内存区,只不过系统把这个内存区看成文件,并且按照文件方式进行管理。这个文件中存放的都是实时从操作系统的各个部分收集来的动态数据,进程通过访问这个文件不但可以方便地获得内核当前的运行状况和内部数据信息,并且还可以对其进行修改和配置。下面是使用Proc文件系统的优点:

    • 可以利用Proc文件系统的文件,开发一些专门用于获取内核数据的应用程序;
    • 完成用户空间和内核空间的通信,能得到内核运行时的数据,安全且方便;
    • 利用Proc文件可使进程直接对内核的参数进行配置的特点,可以在不重新编译内核的情况下优化系统配置。

    参考文章:深入理解linux系统下proc文件系统内容

     

    展开全文
  • Linux 虚拟文件系统(一)概述

    千次阅读 2017-04-16 21:04:26
    Linux (虚拟)文件系统tags: Linux源码Linux 虚拟文件系统 文章梗概 正文 文件系统 虚拟文件系统架构 虚拟文件系统如何知道可用的文件系统有哪些的 不太喜欢的环节 引用 文章梗概本文首先以“尽量不涉及源代码”的...

    Linux 虚拟文件系统(一)概述

    tags: Linux源码



    文章梗概

    本文首先以“尽量不涉及源代码”的方式讨论Linux虚拟文件系统的存在的意义、实现方式;后续文章中以读文件为例从面到点更有针对性的讨论其实现。在讨论的过程中有一些地方可能说的不够全面,一是能力有限;另一方面是希望不要陷入过多的细节之中,将注意力集中在框架的设计上。希望读者有一些编程基础、操作系统概念。本文讨论的Linux内核版本为2.6.24

    正文

    文件系统

    常用的文件的读写的方式有同步读写异步读写内存映射。前两种的主要区别是,同步读写会在进程向操作系统发出读写请求后被阻塞,直至所请求的操作完成时读写的函数才会返回。也就是说,函数返回的时候数据已经从磁盘中读到内存中了,或者已经从内存中写入到磁盘上去了;异步读写在发出读写请求后,函数会立即返回并不等待操作完成,这样的话一般有一个回调函数的存在,操作完成时操作系统会调用用户设置的回调函数;至于内存映射使用的则是缺页机制。这篇文章中主要围绕同步读写的方式,也是最常用的方式,讨论Linux的虚拟文件系统的实现原理。
    要想说明白虚拟文件系统的作用就必须要了解文件系统的作用。对于一个特定的文件系统来说,最主要的的设计方面就是数据在磁盘上的存储方式,这个功能从应用程序猿的角度来看就是文件名到数据的映射 : 通过对 以文件名为主要的参数调用特定的函数(不同的语言、平台函数不同)完成文件的读写操作。而磁盘基本上可以看做一个以扇区(通常为521Byte)为基本存储单位的超大数组。如果有如下的极其简单的文件系统,

    极简文件系统

    扇区0存放着一整块磁盘的属性,如块大小、文件系统标记;1~6中存放着文件的属性和位置信息,每个文件目录项占两个磁盘块,也就是说该文件系统的设计最多可以存放三个文件;1、2中存放着文件test.txt的属性信息(日期、大小、归属)和位置信息;3、4存放着艳照门1.png的属性信息和位置信息;7~15中存放着实际的数据,不同的数据的颜色不同。如图示的文件系统最多只能存放三个文件,很难有实际的用途,不过用来说明文件系统的作用是很合适的,避免陷入过多的细节之中。
    加入现在用户想要读取查看艳照门1.png,那么文件系统要做的事情是这样的 :

    1. 产生读入1、2块磁盘数据的请求,将请求发送给磁盘的驱动程序,等待数据读入到内存后,查看文件的名字,发现文件的名字并不是艳照门1.png
    2. 产生读入3、4块磁盘数据的请求,将请求发送给磁盘的驱动程序,等待数据读入到内存后,查看文件的名字,发现名字匹配正确。然后分析目录项数据,得知艳照门1.png主要存储在12~15四个磁盘块上。
    3. 产生读入12~15四个磁盘块的请求,将请求发送给磁盘的驱动程序,等待数据读入到内存后即可按照png文件的格式解析数据然后将图像呈现在用户面前。

    这里有几点点需要说明一下

    1. 真正的读写磁盘的操作并不是文件系统来完成的,而是特定的磁盘的驱动程序来完成的。磁盘的驱动程序需要的参数是逻辑磁盘块号对应的内存位置是读请求还是写请求。由磁盘驱动程序来完成读写的目的是,实现文件系统的设计和具体磁盘结构的分离。也就是说,我们上面设计的极简的文件系统在驱动程序的帮助下无论是在机械硬盘上面,还是在固态硬盘上面实现方式是相同的。磁盘驱动程序更加的贴近硬件设备,更加的“了解”硬件。譬如,如果使用的是固态硬盘那么驱动程序则不会对读写请求进行排序;如果使用的是机械硬盘,则会对读写请求进行排序。参考机械硬盘内部硬件结构和工作原理详解可知对于机械硬盘,按照顺序1、2、3读取磁盘块的速度是快于1、3、2速度的,所以磁盘驱动程序读写请求排序所做的事情简单讲就是将1、3、2这样的读写请求排序成为1、2、3这样的顺序,然后发送给磁盘控制器(硬件)。而固态硬盘更贵的原因在于其读写过程不包含物理属性(移动磁头),请求1、2、31、3、2和请求2、3、1的速度都是一样的,所以不需要重排请求。
    2. 1 中提到的请求排序的专业术语叫做I/O调度,这一工作应该是由驱动程序完成的,只不过内核提供了一些的常用算法的实现,方便了驱动程序的开发而已。
    3. 一个对特定文件的读写请求可能会产生很多个对磁盘的读写请求。如上所说,要读文件首先要把文件的固有属性读到内存中加以分析,然后才能去读实际的文件。

    虚拟文件系统架构

    上文以比较易懂的方式说明了文件系统一个最重要的工作文件名到磁盘数据的映射,可是单从这一个方面似乎看不出来虚拟文件系统存在的意义。那是因为,实际上文件系统要考虑很多的事情 :

    1. 首先要考虑的一个重要的方面就是,磁盘和内存的速度差距。众所周知,磁盘的速度慢但是每单位空间价格更加便宜,而内存的速度基本上是磁盘的105,这之间的差距还是非常大的。用户读写文件的时候经常存在着这样的行为,刚刚读写过的文件,很有可能再次读写,所以引入缓存的概念是十分必要的。缓存所做的就是在读文件数据到内存之后,找个地方把数据存起来,内存不紧张的话,尽可能长时间将数据保存在内存之中。如果再次读文件,文件系统就去查看是不是在缓存中已经有对应的数据了,如有的话就不需要再次去磁盘上读取数据;实在没有的话,才需要向驱动程序发出读请求。用户是意识不到缓存的存在,所以从用户的角度来看这将极大的加快了数据的读取速度。不过要说缺点的话,这样的设计可能会占用比较多的内存空间,使文件系统和内存管理变得更加复杂。不过现阶段的PC平台内存并不是性能瓶颈,而且为了速度和用户体验这些都是值得的。
    2. 可想而知,缓存的单位指定不能是字节。如果是字节的话需要记录文件的每个字节缓存在内存的哪个位置,这样是不现实的。缓存的单位至少也是和磁盘扇区一样大的,或者是多个连续的扇区存放在一块。以上面的最简文件系统为例,可以很轻松的设计一个这样的数据结构来记录艳照门1.png的第一块也就是磁盘索引的12逻辑块存放在内存的0xFFAA处、第二块到第四块存放在0xAABB处。为了和内存管理模块更好的交互,Linux中的针对文件数据的缓存的单位为,通常大小为4KB,也正是内存管理模块使用的内存单位。这里需要读者有一定的操作系统的基础,能够大体上理解分页机制存在的原因以及做了什么事情,由于篇幅原因这里只需要知道在Linux中,内核使用struct page结构体来描述内存中的每一页。找到一页对应的page结构体就相当于知道了对应的物理页的物理地址、是否被占用等等很重要的属性。这些文字是想说明,文件系统需要和内存管理模块协调工作,毕竟分配回收缓存的内存空间等操作都是需要内存管理模块支持的。
    3. 第三个要考虑的部分和第一个类似,这个机制叫做“预读机制”。类似于,在浏览网页的时候有些浏览器能够提供预读,看完当前的网页点击下一页之后,下一页面能够非常快的呈现在面前。这里的预读机制也就是这个意思,尤其是对于一些比较大的文件。用户第一次想要的可能就是前1kb,这个时候文件系统向驱动程序发出的读请求是大于1kb的,可能是4kb、可能是1mb,多读出来的数据就存在上面提到的缓存。可以看出来预读机制缓存机制是完美结合的,协同工作的。
    4. 1中提到的这个缓存指的是对文件内容的缓存,还有一种缓存是针对目录项的缓存。回顾上文,如果读取艳照门1.png之后,用户又想查看文件test.txt,文件系统又要多次读取1~6块磁盘来查找是不是有test.txt这个文件。这样的话,引入一个针对文件名的缓存也是很重要的,这个缓存在Linux内核中叫做目录项缓存。和上面的缓存类似,只不过是针对目录项的。
    5. 权限检测也是文件系统要做的很重要的一个工作,尤其是在Linux系统上面,经常会遇到读写文件时permission denied的情况。如果没有管理员权限,操作系统(文件系统)是不会让你去读写一些受保护的文件的,window中可能感受不是那么强烈。不过除了这中常规意义上的限制,权限检测还包括:文件是否越界、是否在读写一个目录项文件等操作。
    6. 每个进程都有都会以自己特定的方式(读、写)打开文件,且文件读取的当前位置也是特定于进程的,这些属性是需要记录的。而且对于一个文件很多时候可能会有多个进程同时去读写的情况,如何协调多个进程之间的读写关系,不至于出现错误的情况,也是文件系统设计时需要考虑的一个关键方面。
    7. 锁机制、命名空间等其他的一些部分。

    回顾这么多设计一个文件系统需要注意的地方可以发现,上面的几条对于每一个文件系统都是需要的。也就是说,不管是上面提到的极简文件系统还是在实际使用中的FAT、EXT文件系统,都需要考虑上面的这些因素。为了加快内核的开发、方便后续内核的扩展重构、使内核设计的更加优雅这才提出了虚拟文件系统的概念。虚拟文件系统做的事情就是实现了这样一个框架,在这个框架中上面提及的这些重要因素都有了默认的实现,需要特定的文件系统实现的为文件相对块号到磁盘逻辑块号的映射关系目录项的解析方式等。
    文件相对块号就是指的相对于文件来说是第几块,磁盘逻辑块号指的是相对于磁盘来说是第几块。

    也就是说,如果想让内核识别极简文件系统需要该文件系统的设计人员严格按照虚拟文件系统的架构编写需要的函数(都是函数指针的技术实现的),然后将文件系统注册到内核中去。

    (在这之前文件系统和虚拟文件系统的概念界限是有点模糊的,从这里开始一直到文章的最后,文件系统只是表示磁盘上的数据存储的结构,其他的部分都算在虚拟文件系统里面的 )

    虚拟文件系统之所以没有实现这两个方面是因为这些性质是特定于一个文件系统的。还是上面读取艳照门1.png的例子,在极简文件系统中艳照门1.png第一块是存放在磁盘逻辑12块中的,也就是文件相对块号1->磁盘逻辑块号12。而如果使用的是FAT文件系统那么就可是其他的映射关系。目录项的解析方式需要特定的文件系统来实现就更好理解了,不同的文件系统其目录项的字段设置、顺序、长度通常是不一样的,所以需要让特定的文件系统来解析目录项。解析完之后返回一个统一的文件的表示,也就是大名鼎鼎的inodestruct inode的字段非常之多,对于一些没那么复杂的文件系统来说可能是一种浪费,因为它根本用不到那些复杂的字段。但是虚拟文件系统的设计理念是宁滥勿缺 : 毕竟要尽可能地覆盖所有的文件系统,多的字段你可以不用,但是如果想用却没有那就麻烦大了。

    这个时候看一下Linux虚拟文件系统的整体结构,再合适不过了。

    此处输入图片的描述

    虚拟文件系统(VFS,virtual file system)需要和各个实际的文件系统ext3、… 、reiserproc交互,大多数文件系统都需要虚拟文件系统提供的缓存机制(Buffer Cache),而proc文件系统不需要缓存机制是因为其是基于内存的文件系统。那么按照上面的讨论其需要做的就是完成文件逻辑块号内存中数据块之间的映射关系。再往下一层就是具体的设备驱动层,实际的读写操作都是需要设备驱动层去完成的,它下一层就是实际的物理设备了。

    虚拟文件系统如何知道可用的文件系统有哪些的

    上面提到的特定于文件系统的操作是通过注册的方式让虚拟文件系统知道当前内核中支持哪些操作系统,注册的主要参数有文件系统的名字解析inode的函数(解析目录项)解析文件相对块号到磁盘逻辑块号的函数,这都是上面讨论过的关键点。对于一些常用的文件系统不用注册也能够使用,这是由操作系统去注册的。注册使用的技术就是C语言中的函数指针。注册完成之后,就可以通过挂载的方式去使用一个具体的文件系统了。挂载需要的参数有被挂在的设备(本文讨论中限定为磁盘)该设备使用的文件系统(必须已经注册过)挂载点。如果明白前文的讨论,那么挂载也是很好理解的。以上文的极简文件系统为例,艳照门1.png存放在磁盘A中,在磁盘A没有被挂在之前操作系统(或者说虚拟文件系统)并不知道磁盘A使用的什么文件系统,所以没有办法去读取它上面的数据并解析之。在用户执行了操作以极简文件系统挂载磁盘A到 /home/jingjinhao/片 下之后,在访问/home/jiangjinhao/片/艳照门1.png的时候虚拟文件系统就会调用极简系统注册的函数,去执行前文讨论过的寻找艳照门1.png的过程。毫无疑问操作系统需要维护一个目录之间的层级关系以及不同的文件系统之间的挂载关系,这正是struct dentrystruct vfsmound的作用。这之间的具体图示关系请参考mount过程分析之六——挂载关系(图解) 。感觉自己没有能力写出来一篇比这还好的文章,推荐看一下这篇文章。

    不太喜欢的环节

    上文提到struct inodestrcut dentrystruct vfsmound这三个数据结构都是虚拟文件系统非常重要的部分。虽然不大喜欢扣数据结构,不过为了下文更好的讨论这里还是尽量从原理上罗列一下核心数据结构。

    1. struct address_space这个数据结构是对上文讨论过的缓存的抽象。该数据结构可以提供查找缓存、添加缓存的方法,也就是说对于一个文件找到了其对应的struct address_space就能够增删改查缓存的内容。暂时不必关心起底层的实现是链表、数组还是树(其实是基数树),无论是什么其提供的功能总是不变的,只不过速度上可能会有差别。查找使用的参数是文件相对页号,成功返回对应的物理页帧描述结构struct page的指针(上文描述过),没有找到的话返回null。这里的文件相对页号很好理解,举例来说在页大小为4KB的情况下,0~4KB对也相对页号为0,4KB~8Kb对应的相对页号为1,以此类推。
    2. struct inode是对一个文件的抽象,所以其中包含的主要字段有 : 文件的大小、日期、所有者等固有属性;指向缓存的指针struct address_space *;指向块设备驱动程序的指针block_device*,因为文件系统并不负责实际的读写,需要依靠驱动程序的帮助;一些锁。这几大类字段,在上文的讨论下都是比较好理解的,需要说明的一点就是inode中是没有文件的名字这个字段,文件的名字包含在下面的dentry中,所以取而代之的是指向对应文件的struct dentry的指针。这并不是说一定不能把文件名存储在inode中,只不过当前虚拟文件系统的设计使然,再在inode中存储的话就有点啰嗦了。
    3. struct dentry首先实现了对目录层次结构的抽象,如下图目录层次结构内存中每个打开的的每个节点都对应一个struct dentry的实例,需要强调的不仅仅目录有对应的detry实例,普通的文件也有对应的detry,只不过普通文件的detry实例没有子节点罢了。只有打开的文件或目录才有对应的节点,所以内存中树结构的完整度是磁盘上树结构的完整度的;没有在inode中而是在detry存储文件的名字的一大原因struct detry负责建立起前文讨论过的目录项缓存(以Hash表的方式)。也就是说在打开一个文件的时候,虚拟文件系统会首先通过文件名查找是否存在一个打开的detry了,如果有的话就大可返回了;detry最后一个重要的作用就是结合struct vfsmount完成了挂载操作的数据结构的支持。上图中的示例在vfsmount的视图中如下图示 vfsmount视图
      此外硬链接的实现也是需要detry的支持的。
    4. 正如上面所说虚拟文件系统需要记录某个进程操作一个文件的方式、当前位置等属性,这些属性是特定于一个进程的,一个文件可能同时存在多种被打开的状态,由此引入了struct file结构体。该结构体是对一次文件操作的抽象,刚刚提到的几个方面外,file中还包含了预读相关的一些字段。每个进程控制块struct task中都包含一个struct file *的数组,进程打开的每个文件对应其中的一项,这也解释了为什么fopen返回的是一个无符号整型了(数组的索引)。
    5. 除了上面讨论的四大方面的属性,还有一个方面的属性可以用一个单独的数据结构抽象出来,这就是特定于一个文件系统的属性,譬如极简文件系统的最多只能存三个文件这类似的属性,这个结构体叫做struct super_block。以极简文件系统为例其对应着磁盘逻辑地址0的块中的数据。

    通过上面的讨论就可以通过下图来纵观虚拟文件系统的结构了,该图引自深入Linux内核架构中文版418页,请暂时忽略各个*_operations,其余的不外乎刚刚讨论过的五个结构体,希望读者能够认真看一下这个图片。
    虚拟文件系统整体结构

    图中的几个*_operations都是一些函数指针的结构体,注册文件系统的精髓就是将自己实现的功能函数以函数指针的形式传递给虚拟文件系统。
    譬如对于ext2文件系统其对应的address_space_operations

    const struct address_space_operations ext2_aops = {
        .readpage       = ext2_readpage,
        .readpages      = ext2_readpages,
        .writepage      = ext2_writepage,
        .sync_page      = block_sync_page,
        .write_begin    = ext2_write_begin,
        .write_end      = generic_write_end,
        .bmap           = ext2_bmap,
        .direct_IO      = ext2_direct_IO,
        .writepages     = ext2_writepages,
        .migratepage    = buffer_migrate_page,
    };
    //重
    static int ext2_readpage(struct file *file, struct page *page)
    {
        //@ page 要读的相对于文件的页号
        //特定于ext2文件系统的 相对文件块号->磁盘逻辑块号 映射关系 函数
        return mpage_readpage(page, ext2_get_block);
    }

    其中比较重要的下篇文章可能用到的为ext2_readpage函数,该函数直接调用了mpage_readpage,这个函数是虚拟文件系统提供的,ext2_get_block是ext2文件系统提供的。下篇文章还有相关的讨论,这里不再赘述。
    另一个比较重要的函数为inode_operations->look_up = ext2_lookup这个函数就上文一再强调的解析目录项的函数。


    引用

    本文使用的引用基本上都在文中以超链的方式给出了,侵删。还需要声明一下,更多的是对现有博客和书籍的补充,具体的实现请参照Linux三本经典书籍

    展开全文
  • 虚拟化、文件系统、查找文件

    万次阅读 2019-11-27 12:27:27
    文章目录虚拟虚拟化的概念安装KVM安装gustos了解并配置KVM网络桥接:NAT:仅主机(hostonly):文件系统了解文件系统的概念:了解硬链接的概念:挂载文件系统:查找文件: 虚拟虚拟化的概念 虚拟化≠虚拟机 虚拟化...
  • Linux 虚拟文件系统(VFS)介绍

    万次阅读 多人点赞 2016-05-27 21:40:20
    1. 通用文件模型Linux内核支持装载不同的文件系统类型,...为支持各种文件系统,Linux内核在用户进程(或C标准库)和具体的文件系统之间引入了一个抽象层,该抽象层称之为“虚拟文件系统(VFS)”。VFS一方面提供一...
  • 虚拟文件系统——更好的文件抽象层任何一个软件设计的难题都可以通过增加一个抽象层来解决 。我们的系统开发中,经常遇到一些难办的事情,比如,一台linux服务器上,从源里安装了一套apache+php+mysql,然后另外一个...
  • Linux 虚拟文件系统(二)Mount、Open;设备文件、挂载和打开文件 tags: Linux源码 Linux 虚拟文件系统二MountOpen设备文件挂载和打开文件 梗概 挂载 设备文件 设备文件从哪里来的 挂载做了什么 打开文件 打开...
  • Linux2.6--虚拟文件系统

    千次阅读 2013-08-14 10:10:33
    虚拟文件系统(有时也称作虚拟文件交换,更常见的是简称做VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口.系统中的所有文件系统不但依赖VFS共存,而且也依赖VFS系统协同工作.通过虚拟文件系统,程序...
  • 虚拟文件系统-VFS介绍

    千次阅读 2013-02-11 18:05:36
    虚拟文件系统-VFS介绍 作者: admin 日期: 2011 年 6 月 7 日发表评论 (0)查看评论 虚拟文件系统(VFS) 在linux Ext文件系统的开发过程中,引入了一个非常重要的概念,即虚拟文件系统 (VFS)。...
  • 虚拟文件系统与真实根文件系统

    千次阅读 2016-05-05 09:21:21
    引言:根文件系统的noinitramfs已经分析,继续上文未完的initramfs和Android根文件系统分析,这两者有什么关系?1.initramfs对于initramfs,kernel 2.5开始引入,其实质是在内核镜像中附加一个cpio包(cpio一个用于...
  • 1、课程设计的目的 本课程设计是学生学习完《操作系统...了解EXT2文件系统,设计一个类EXT2型文件系统,所设计的文件系统要具备文件系统格式化、用户登录、用户注销、显示目录内容、文件创建、文件删除、目录创建...
  • 基于跨平台的文件系统和windows虚拟文件系统 缘起:这个想法来自于我们学校的一个课程设计,虽然他们做的课程设计要求不是很高,但是却给了我一个提示,就是一个跨平台的文件系统的可实现性和一个虚拟文件系统的...
  • Linux虚拟文件系统(概述)

    千次阅读 2012-02-08 09:58:54
    Linux虚拟文件系统是一个内核软件层,用来处理与UNIX标准文件系统相关的所有系统调用。其健壮性表现在能为各种文件系统提供一个通用的接口。 Linux虚拟文件系统支持的文件系统可以划分为三种主要的类型: 磁盘文件...
  • /proc 虚拟文件系统用作查看和配置系统内核参数的接口。/proc 是一个层次结构的目录其中包含了 系统内核的当前设置值。之所以称为/proc 是因为该虚拟文件系统通常发送信息给别的操作系统进程。 虚拟文件系统不会...
  • linux的虚拟文件系统一(框架)

    千次阅读 2018-10-01 00:28:43
    1.什么是文件系统 文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易,文件系统使用文件和树形目录的抽象逻辑概念 代替了硬盘和光盘等物理设备是使用数据块的概念,用户使用文件系统来保存...
  • 一、VFS 虚拟文件系统基础概念  Linux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件系统的存在。虚拟文件系统,即VFS(Virtual File System)是 Linux 内核中的一个软件抽象层。它...
  • linux下使用kpartx挂载虚拟文件系统

    千次阅读 2018-05-15 16:31:02
    linux下使用kpartx挂载虚拟文件系统在linux中,如果映像文件(.img)含有分区表的话,那么用losetup这个程序来加载文件系统就有点力不从心了。因为losetup只能加载无分区的文件系统映像文件。不过有一个好东西配合...
  • linux 内核编程之proc虚拟文件系统

    千次阅读 2014-01-01 15:22:42
    【版权声明:转载请保留出处:.../proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux 内核空间和用户空间之间进行通信。在/proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信
  • 这篇文章是《读薄「Linux 内核设计与实现」》系列文章的第 VI 篇,本文主要讲了以下问题:Linux 虚拟文件系统的概念、相关接口等内容。 0x00 虚拟文件系统概念 虚拟文件系统(VFS)为用户空间提供了文件系统接口 VFS...
  • VFS(Virtual Filesystem Switch):虚拟文件系统,是一个目录树。树上不同的节点可以映射到物理的文件地址,可以挂载。 相当于一个解耦层,在具体的文件系统之上抽象的一层,为能够给各种文件系统提供一个通用的...
  • Linux 的虚拟文件系统(强烈推荐)

    万次阅读 多人点赞 2016-06-03 16:37:08
    1 引言 Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等。...如图 1 所示,我们可以使用 cp 命令从 vfat 文件系统格式的硬盘拷贝数据到 ext3 文件系统格式的硬盘;而这样的操作涉及到两个不同的文
  • 简单虚拟文件系统的设计与实现

    千次阅读 2011-11-24 11:11:25
    简单虚拟文件系统的设计与实现  -----云风Windsoul源码剖析    虚拟文件系统(VFS)是由Sunmicrosystems公司在定义网络文件系统(NFS)时创造的。它是
  • 理解linux虚拟文件系统VFS - 概述

    万次阅读 2013-07-25 14:43:07
    当前,除了linux标准的文件系统Ext2/Ext3/Ext4外,存在很多种文件系统,比如reiserfs, xfs, Windows的vfat NTFS,网络文件系统nfs 以及flash 文件系统jffs2, yaffs/yaffs2 ubifs。linux通过叫做VFS的中间层最这些...
  • 什么是文件系统,详见:http://zh.wikipedia.org/zh/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F 其实一句话就是管理这块文件的机制(组织方式,数据结构之类...) Linux系统中存在很多的文件系统,例如常见的ext2,ext3,ext...
  • fuse 虚拟文件系统 的 安装与使用

    万次阅读 2011-03-03 16:50:00
    FUSE 是个好东西, 可以用在特殊的领域里面来实现自己的虚拟文件系统。   FUSE的下载与安装 : 从fuse官网下载最新安装包:http://sourceforge.net/projects/fuse/files/fuse-2.X/<br /> ...
  • 并行虚拟文件系统(PVFS) _曹强

    千次阅读 2012-04-05 11:59:15
    并行虚拟文件系统(PVFS) PVFS [2](Parallel Virtual File System)项目是Clemson大学为了运行Linux集群而创建的一个开源项目,因此,PVFS也无需特别的硬件设备。普通的能运行Linux系统的PC机即可。PVFS现已被...
  • STSdb是什么 再来说明一下STSdb是什么:STSdb是C#写的开源嵌入式数据库和虚拟文件系统,支持实时索引,性能是同类产品的几倍到几十倍,访问官方网站。
  • Linux支持各种各样的文件系统格式,如ext2、ext3、reiserfs、FAT、NTFS、iso9660等等,不同的磁盘分区、光盘或其它存储设备都有不同的文件系统格式,然而这些文件系统都可以mount到某个目录下,使我们看到一个统一的...
  • Linux内核大讲堂 (三) 督脉之虚拟文件系统(1) 在上一节内核大讲堂 (二) ...上层是虚拟文件系统,显然下层就是非虚拟文件系统了,就是“实际”的文件系统。什么才算实际?呵呵。高中学过反证法,这时候你就感

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 706,775
精华内容 282,710
关键字:

什么是虚拟文件系统